May 20, 2026

Why a browser canvas wipes C2PA credentials

C2PA — the Coalition for Content Provenance and Authenticity — is the system Adobe, Microsoft, and friends use to sign AI-generated images. On Instagram and Facebook, a signed C2PA manifest is what triggers the "Made with AI" label.

The signatures are cryptographic. The manifests are tamper-evident. It sounds robust.

It is, until you remember one detail: C2PA travels in a container, not in the pixels.

What a JPEG actually looks like

A JPEG file is a series of markers. The pixels live inside SOI, SOF, DQT, and SOS segments. Metadata — EXIF, XMP, IPTC, ICC, and C2PA — lives in APP* segments alongside them. PNG works the same way with tEXt, iTXt, and dedicated caBX chunks for C2PA.

When you open the file in a browser, the decoder reads the pixel segments into a raw bitmap. It walks past the metadata.

What <canvas>.toBlob() does

const canvas = document.createElement("canvas");
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
canvas.getContext("2d").drawImage(img, 0, 0);
canvas.toBlob(blob => { /* clean file */ }, "image/jpeg", 0.95);

The browser re-encodes a brand-new JPEG (or PNG, or WebP) from the in-memory bitmap. There is no metadata to copy, because the bitmap has none. C2PA manifests, EXIF GPS, Stable Diffusion parameters chunks — all of it lived outside the pixel grid, and none of it survives.

What this does not fix

The takeaway

A 30-line HTML file does in your browser what a backend service charges $5/month for. The privacy story is honest because there is no server to trust — disconnect from the internet after the page loads and the tool still works.