C2PA Explained: The Open Standard Behind AI Image Authentication
C2PA is the technical backbone of EU AI Act compliance for AI-generated images. Adobe, Microsoft, OpenAI, and Google are all implementing it. But how does it actually work? What's inside a manifest? Why do self-signed certificates get rejected? And what does it take to sign correctly?
What is C2PA?
C2PA stands for Coalition for Content Provenance and Authenticity. It's a technical standard — not a product or a company — maintained by a joint development foundation that includes Adobe, Microsoft, Intel, Arm, BBC, Truepic, and now OpenAI and Google, among others.
The standard specifies a way to embed cryptographically signed provenance metadata into media files. "Provenance" here means: who created this file, with what tool, what actions were performed on it, and who published it. Each of these claims is signed with an X.509 certificate, making the chain tamper-evident.
C2PA is also the technical specification underlying Content Credentials— the consumer-facing brand Adobe and the Content Authenticity Initiative (CAI) use for end-user tooling like inspect.cr and contentcredentials.org.
How the manifest is stored in an image file
A C2PA manifest is stored in a container format called JUMBF(JPEG Universal Metadata Box Format, ISO 19566-5). For JPEG files, the JUMBF box is placed in the APP11 segment. For PNG, WebP, and other formats, equivalent container mechanisms are used.
The JUMBF box contains one or more manifests, each of which is a set of signed claims about the asset. A manifest has three main components:
ClaimThe top-level signed statement. Contains references to all assertions made in this manifest, a hash of the asset content, the claim generator's identity, and the digital signature.
AssertionsIndividual factual claims about the asset. Standard assertion types include c2pa.actions.v2 (what was done to the image), c2pa.hash.data (content binding hash), c2pa.ingredient.v3 (what source materials were used), and custom assertions for app-specific metadata.
IngredientsReferences to parent assets — for example, a photograph that was edited into the current image. Each ingredient includes a reference to its own C2PA manifest, creating a chain of provenance.
What a manifest actually looks like
Internally, manifests are stored as CBOR (Concise Binary Object Representation). But the C2PA tooling exposes them as JSON. Here's a minimal example of what an AI-generated image manifest looks like — simplified from the actual spec:
{
"claim_generator": "DALL-E/3.0 c2pa-rs/0.5",
"claim_generator_info": [{
"name": "DALL-E",
"version": "3.0",
"icon": { "format": "image/svg+xml", "identifier": "openai-icon" }
}],
"title": "generated-image.jpg",
"format": "image/jpeg",
"assertions": [
{
"label": "c2pa.actions.v2",
"data": {
"actions": [{
"action": "c2pa.created",
"softwareAgent": {
"name": "DALL-E",
"version": "3.0"
},
"when": "2026-03-06T09:15:00Z",
"digitalSourceType":
"https://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia"
}]
}
},
{
"label": "c2pa.hash.data",
"data": {
"alg": "sha256",
"hash": "DcGR4k9M6aLXXCeDii4tSdX45rrIM5HSr1Wy/czQ6ro=",
"exclusions": [{ "start": 20, "length": 51179 }]
}
},
{
"label": "c2pa.ai_generative_training",
"data": { "use": "notAllowed" }
}
],
"signature_info": {
"alg": "es256",
"issuer": "OpenAI, Inc.",
"cert_serial_number": "7a3f1c..."
}
}A few things to note: The c2pa.hash.data assertion binds the manifest to the exact pixel content of the image via a SHA-256 hash with exclusions (the exclusions allow the JUMBF box itself to be part of the file without creating a circular hash dependency). If a single pixel changes after signing, the hash validation fails. The c2pa.ai_generative_trainingassertion records whether the image may be used for AI training. The digitalSourceType field uses IPTC vocabulary to precisely characterize the type of generation.
The actions vocabulary: what happened to this image
The c2pa.actions.v2 assertion carries the history of transformations. The C2PA specification defines a standard vocabulary of actions. The most relevant ones for AI-generated images:
| Action | Meaning |
|---|---|
| c2pa.created | The asset was created from scratch — used for AI-generated images |
| c2pa.published | The asset was published/distributed — used by the deployer |
| c2pa.edited | Pixel-level modifications were made (cropping, retouch, color) |
| c2pa.transcoded | Format conversion (JPEG→WebP, etc.) without content change |
| c2pa.repackaged | Rewrapped in a different container without content change |
| c2pa.placed | Used as an ingredient in another asset |
| c2pa.unknown | An action was taken but the type is unspecified |
When MarkMyAI adds a publisher claim, we use c2pa.publishedto record the deployment event — with your organization name, timestamp, and purpose. This is distinct from the AI tool's c2pa.createdclaim and builds on top of it.
Signing: certificates, chains, and the trust list
Every C2PA manifest must be cryptographically signed with an X.509 v3 certificate. The signature covers all assertions in the manifest, making any tampering detectable. The supported signature algorithms are ES256, ES384, ES512 (ECDSA), and PS256, PS384, PS512 (RSA-PSS).
Here's where most developers hit the first wall. We certainly did. You cannot use a self-signed certificate. The c2pa-rs library (the Rust core underlying all C2PA implementations) enforces this at signing time. If a manifest is signed with a self-signed certificate, you get back "the certificate is invalid." That's it. No further context, no suggestion of what's wrong, no hint that a chain is required. We spent the better part of three days on this error before understanding what it actually meant.
The reason: C2PA's security model requires a certificate chainthat terminates at a trusted root certificate authority (CA). The chain typically looks like this:
Certificate chain (required)
Root CA Certificate ← trusted by C2PA trust list
↓
Intermediate CA Cert ← issued by Root CA
↓
End-Entity (Signing) Cert ← your certificate, identifies your org
Self-signed cert ← REJECTED by c2pa-rs ✗
For production use, you must purchase a signing certificate from a CA on the official C2PA Trust List. As of January 2026, approved CAs include SSL.com, Trufo, and DigiCert. The certificate must include the Organization Name (O attribute) in its distinguished name — this is what appears as the signer identity in tools like Adobe's inspect.cr. Without the O attribute, you'll be listed as "Unknown Organization" regardless of how correctly everything else is configured. We missed this on our first production attempt.
The trust list: why "Unknown Signer" appears
When you upload an image to contentcredentials.org and see "Unknown Signer" or "Unverified," it means the certificate used to sign the manifest is not on the C2PA Trust List. The signature itself may be mathematically valid — the manifest hasn't been tampered with — but the signer cannot be identified as a trusted entity.
The C2PA Trust List was launched in mid-2025 as part of the C2PA Conformance Program. It replaced the earlier Interim Trust List (ITL). The ITL remained operational through December 31, 2025; existing ITL certificates remain valid for legacy support but new signers must use the full trust list.
For MarkMyAI's beta, we use the official c2pa-node test certificate chain — which validates the signature mathematically but appears as "Unknown Signer" in consumer tools. It's a deliberate trade-off: we wanted to ship and test the full pipeline before going through the CA vetting process, which takes 1–3 business days and requires proving your organization identity. Before public launch, we'll replace this with a production certificate from a trust-listed CA.
For developers building C2PA integrations
During development, use the test certificates from the c2pa-node repository. For production, purchase a certificate from SSL.com, Trufo, or DigiCert. Expect the process to take 1–3 business days including the organization vetting.
C2PA spec version history: what changed in 2.x
The current production version is C2PA 2.1/2.2. Several changes from 1.x are important to know:
Ingredients are now V3 (c2pa.ingredient.v3)
The ingredient assertion format changed. Old c2pa.ingredient entries from C2PA 1.x files are still readable but new manifests must use v3.
SoftwareAgent is now ClaimGeneratorInfo
Previously SoftwareAgent was a plain string. It's now a structured object with name, version, and optional icon. This enables richer display in tools.
Training/data mining assertions replaced
Old c2pa.data_mining, c2pa.ai_training, c2pa.ai_generative_training, c2pa.ai_inference have been replaced by CAWG (Creator Assertions Working Group) assertions for training and data mining.
First action must be 'opened' or 'created'
Every manifest in C2PA 2.x must start with either a c2pa.opened or c2pa.created action as the first entry in the actions array, each with an associated ingredient.
Soft binding support added
C2PA 2.1 introduced decoupled (soft) binding for cases where direct in-file embedding is not possible — for example, embedding provenance in a hosted manifest rather than the file itself.
Tools for working with C2PA
| Tool | Type | Use |
|---|---|---|
| inspect.cr (Adobe) | Web UI | Human-readable C2PA manifest viewer with trust status |
| contentcredentials.org | Web UI | Consumer-facing manifest verification with trust indicators |
| c2patool (CLI) | CLI | Read/write C2PA manifests from the command line |
| c2pa-node | Node.js library | Server-side C2PA signing and reading — what MarkMyAI uses |
| c2pa-rs | Rust library | The core Rust implementation all other tools are built on |
| c2pa-python | Python library | Python bindings for c2pa-rs |
| @contentauth/c2pa | Browser JS | Client-side C2PA reading (verify/check pages) |
The hard limits
C2PA is powerful but not magic. The standard itself is clear about what it can and cannot guarantee:
Tamper detection: any modification to the image or manifest after signing is detectable via hash validation failure.
Signer identity: the signer's certificate identifies the organization that signed — if from a trust-listed CA, this is verifiable.
Chain of custody: C2PA's ingredient chain can document every transformation from capture to publication.
Metadata survival: C2PA cannot prevent metadata stripping by downstream platforms. This is why database fingerprinting is required as a fallback.
Content verification: C2PA doesn't prove the content is true or non-manipulated — it proves what actions were taken and by whom.
Invisible watermarking: C2PA is a metadata standard, not a steganographic watermarking standard. Separate techniques are needed for pixel-level marks.
Read the C2PA manifest in any image
Upload an AI-generated image to our free checker. We'll decode and display the full C2PA manifest — claim generator, signer, actions, and trust status.