Hero image is MarkMyAI-verified
TechnicalJanuary 15, 2026 · 10 min read

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:

Claim

The 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.

Assertions

Individual 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.

Ingredients

References 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:

C2PA manifest — minimal example (JSON representation)
{
  "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:

ActionMeaning
c2pa.createdThe asset was created from scratch — used for AI-generated images
c2pa.publishedThe asset was published/distributed — used by the deployer
c2pa.editedPixel-level modifications were made (cropping, retouch, color)
c2pa.transcodedFormat conversion (JPEG→WebP, etc.) without content change
c2pa.repackagedRewrapped in a different container without content change
c2pa.placedUsed as an ingredient in another asset
c2pa.unknownAn 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

ToolTypeUse
inspect.cr (Adobe)Web UIHuman-readable C2PA manifest viewer with trust status
contentcredentials.orgWeb UIConsumer-facing manifest verification with trust indicators
c2patool (CLI)CLIRead/write C2PA manifests from the command line
c2pa-nodeNode.js libraryServer-side C2PA signing and reading — what MarkMyAI uses
c2pa-rsRust libraryThe core Rust implementation all other tools are built on
c2pa-pythonPython libraryPython bindings for c2pa-rs
@contentauth/c2paBrowser JSClient-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.

Analytics Consent

We use Google Analytics 4 only if you agree, to understand which pages bring traffic and where visitors drop off. No advertising features are enabled. You can change your choice at any time in the privacy settings.