← research notes
Week 3 January 18, 2026

Reading the C2PA Spec: What It Actually Does and Where the Gaps Are

Spent the week in the C2PA v2.2 specification for ProvStamp. Here's what content credentials actually are, what they don't cover, and the design decisions I'm landing on.

C2PAProvStampAI ComplianceContent Provenance

The actual C2PA spec

I’ve been loosely following C2PA since v1.x, but this week I sat with the v2.2 specification properly. There’s a gap between how it’s described in press releases (“content authenticity”) and what the technical spec actually defines.

Here’s what content credentials actually are at a technical level:

A C2PA manifest is a bundle of metadata attached to an asset. It contains:

  • A claim: a structured record of assertions about the asset
  • Assertions: specific statements about provenance, actions taken, AI involvement, etc.
  • A claim signature: cryptographic signature over the claim using X.509 certificates

The key property is the content binding, a hash of the asset is included in the signed claim, making tampering with the asset detectable. Change a pixel, the hash breaks. The manifest is embedded in the file (JFIF for JPEG, XMP for others) or stored in a sidecar.

For AI-generated content, the relevant assertion type is c2pa.ai_generative_training and c2pa.created. The spec defines how to record that content was produced by generative AI, what model was used, and what training data it was derived from (if known).

What v2.0 changed that matters

Version 2.0 made a significant call: signing is restricted to X.509 certificates only. Before that, the spec allowed various key types. The practical effect is that every signer needs to be either:

  1. Part of the C2PA Trust List (hardware and software signers verified by a root authority), or
  2. Using self-signed certs (which work technically but provide much weaker trust guarantees)

For ProvStamp this matters a lot. We want to be a signing authority for enterprise customers, meaning we need to be a proper CA-issued entity in the chain, not just handing out self-signed credentials.

Where the gaps are

A few things the spec doesn’t handle well:

Audio re-encoding breaks the content hash. If you take a C2PA-signed audio file and transcode it, even losslessly to a different container, the file hash changes and the credential breaks. v2.1 introduced “soft binding” to address this for video, but audio support is incomplete. For Museka this is directly relevant: we’re generating audio and would want to sign it, but distribution platforms transcode everything.

No binding for text output. C2PA is primarily designed for image, video, and audio. There’s no clean mechanism for text documents generated by LLMs. For an Article 50 compliance use case where you want to prove a text document was AI-generated, C2PA alone doesn’t get you there. You’d need a separate layer (MIME type declarations, embedded metadata, something else).

Chain length degrades performance. Each time an asset is modified and re-signed, a new manifest is appended referencing the previous one. For assets that go through many editing steps, the manifest chain gets long. The spec doesn’t define a compaction or pruning mechanism yet.

ProvStamp design decisions

Given the above, I’m landing on:

  • Use C2PA for image and video provenance: this is the core EU AI Act Article 50 use case and the spec handles it well
  • Build a separate layer for text: probably a signed JSON object with a standardised schema, following the spirit of C2PA without the file-format binding
  • Handle the audio gap separately: document the limitation clearly, provide fingerprinting as a fallback for audio content that will be transcoded

The API surface I’m thinking about: POST /sign takes an asset + metadata, returns the asset with embedded C2PA manifest. POST /verify takes an asset, returns the manifest chain and trust status. Simple.

What I was also reading

Nothing directly related, but APT29’s January 2025 campaign targeting European diplomats is worth noting, phishing emails impersonating European Ministry of Foreign Affairs, delivering a new backdoor (GRAPELOADER) via a fake wine tasting event invitation. The social engineering is getting more contextually specific. Check Point published the analysis.

The relevance to my work: spearphishing quality is going up. The ThreatWatch APT feed needs better signal on campaign patterns, not just IOCs. I’ll think about this when I do the feed audit next month.


Next week: the quishing problem. I’ve been seeing a lot of QR code phishing in the wild data and I want to understand the evasion mechanics properly.