FEP-5837: Content Credentials for Media Attachments

Cameras, phones and AI image tools are shipping C2PA Content Credentials now, and almost every fediverse server throws them away the moment a photo gets resized. By the time a post federates, nobody downstream can tell a camera shot from a generated image.

This FEP adds two optional properties to attachments:

  • digitalSourceType, an IPTC Digital Source Type URI, so receivers can label AI generated and AI modified media without parsing C2PA themselves
  • contentCredentials, a small summary of what the origin server found when it validated the upload (validationState, signer, claimGenerator)

It also covers how a server can sign its own resized copy, with the original as the parent ingredient, so the provenance chain survives for anyone who wants to verify the file themselves.

Privacy was a big part of this. Manifests can carry EXIF with GPS, identity assertions and pre-crop thumbnails. The FEP says not to republish any of that, and to redact it from the parent manifest before re-embedding.

1 Like

The GPS location is an interesting one. I agree that it should be stripped by default for privacy, but it also might be interesting to allow the user the option of keeping it and making it visible at the ActivityPub layer, such as translating it into a geotag.

Thank you for working on this proposal. I have a concern about relying on server-reported validation summaries when the distributed image no longer contains its original C2PA manifest.

If a server re-encodes an upload, removes the manifest, and does not sign the derivative, recipients must trust the publisher’s contentCredentials summary. They cannot independently verify that report against the distributed file.

For example, a malicious server could distribute AI-generated images while claiming that they were camera captures with Trusted credentials. A recipient relying solely on those fields would have no cryptographic evidence with which to challenge the claim. It could end up displaying misleading provenance information based entirely on the publishing server’s assertions.

I appreciate that the proposal explicitly identifies the summary as a publisher’s claim. My concern is that, without an independently verifiable asset, trust in the publishing server becomes the sole basis for accepting that claim.

I suspect many smaller instances will be unable or unwilling to take on the cost and operational responsibility of maintaining trusted signing credentials. The optional signed-derivative approach may therefore see limited adoption.

Could preserving and exposing the original signed asset be considered a first-class alternative? This would retain the existing signature without requiring the publishing server to operate its own signing infrastructure. Recipients could independently validate the original using their clients, browser extensions, or external C2PA verification tools.

This would not make every provenance claim inherently truthful, but it would allow recipients to check the signature, assess the signer, and verify the manifest’s binding to the actual file, rather than relying solely on a server-reported result.

In this model, additional ActivityPub properties would not be necessary for cryptographic verification, since the evidence remains available in the original file.

Preserving the original would require explicit author consent, since the file may contain sensitive metadata, including location information. An optimized derivative could still be provided for display, with a clear distinction between that derivative and the signed original.

Yes, that is a great point!

I think we should encourage preserving the data as first class, and with Pixelfed, we have a few optional drivers that are quite performant and could handle this, but and this is where it gets tricky, what you identified as a potential issue with malicious provenance rewriting is really no different than what we would get from servers who strip this during optimization (like Mastodon) and can only really “hope for the best” when it comes to displaying this for users.

I guess it’s up to each implementation on how they want to signal this in their UI, being able to verify the credentials on your own server could be an option for those that want strict provenance chain of custody.

How would withdrawn consent be handled after a signed original or its parent manifest has already federated? The proposal covers redaction before re-embedding, but recipients may have cached the earlier attachment. It would help to distinguish what the origin can remove from what downstream copies may retain, so a consent control doesn’t imply a stronger deletion guarantee than federation can provide.

For me, a key benefit of C2PA is that recipients can independently inspect and validate the provenance of the actual asset. They can check signatures and content bindings, examine the recorded editing history, and inspect ingredients or thumbnails where these are included. This does not eliminate the need to assess the signer’s trustworthiness, but it means we do not have to rely solely on the publishing server’s interpretation.

When only a server-generated summary remains, that capability is lost. We receive a value such as Trusted, but cannot independently examine the evidence behind it or explore the provenance history that was present in the original. I understand that the proposal also allows signed derivatives. My concern is specifically about implementations that distribute neither a verifiable derivative nor an accessible signed original.

There is also an author-choice aspect here. A photographer may deliberately export an image with Content Credentials because they want to share its provenance. Where their editing software provides disclosure controls, they may already have made choices about which information to include. I would like platforms to respect that intention and offer preservation as an explicit option, with a clear warning about any personal metadata that will also be retained.

Privacy protection is important, and export controls may not cover every piece of embedded metadata. However, I think the author should be able to make an informed choice to publish the signed original, rather than having its verifiable provenance automatically removed during processing.

I also agree with the concern about withdrawing consent: preserving an original does not guarantee that federated copies can later be deleted. That limitation should be clearly explained before publication.

Thanks for writing this up. Getting provenance to survive federation is worth doing. Some C2PA-specific notes on the discussion so far, then a review of the draft itself.

On the thread

  • @mczachurski on verifiability. Agreed. It’s worth adding that a server-signed derivative doesn’t fully close the gap either. A parentOf ingredient binds to the parent’s manifest (hashes of its activeManifest and claimSignature), not to the parent’s pixels. A signed derivative is therefore the server attesting “this file came from that one” under its own certificate. What it adds over a plain summary is accountability: the claim is signed and attributable to a named signer, and the parent’s manifest and signature can still be checked independently. Receivers should present it as “signed by server name”, not as the camera’s credential.
  • A middle ground for servers that won’t sign. A server could publish the original’s manifest store as a sidecar .c2pa file, advertised with Link: <…>; rel="c2pa-manifest" (§15.5.3.2). Receivers could then check the signature, signer and editing history themselves. They couldn’t confirm the manifest binds to the displayed pixels, so the asset won’t be a Valid asset, but they would no longer depend on the server’s validationState. The catch: the sidecar carries the same personal metadata, so the redaction rules still apply, and redacting means re-signing.
  • @dansup on “no different from stripping”. I’d push back a little. Stripping produces an absence; a server-reported Trusted produces a positive claim. It may be worth requiring receivers to show “reported by origin” differently from “verified locally”.
  • FenTiger on geotags. The exif:GPS* fields are among those allowed in c2pa.metadata, so offering this as an author opt-in seems reasonable. Once the location is copied into an ActivityStreams location, though, it is no longer signed, so it should be presented as author-provided.
  • lukasmueller on withdrawn consent. C2PA makes this stricter, not looser. Manifests are signed and immutable. Redaction produces a new manifest on a new copy; it doesn’t reach copies that have already federated, or any manifest repository the creator registered with for soft-binding lookup. Consent has to be settled before the first federation. An Update that swaps in a redacted derivative is best-effort only, and I agree with @mczachurski that the FEP should say so.
  • @mczachurski on author intent. Agreed. Since redaction in the FEP is a SHOULD, it could add an explicit exception: “unless the author has chosen to publish the credentials as exported”, with a warning about any personal metadata that would be retained.

On the draft

I read it against the C2PA 2.4 specification it cites, and against the current 2.5 working draft. The section references (§6.8, §14.3) are correct, but a few things don’t line up with C2PA, and one rule produces the wrong label. Section numbers below refer to C2PA 2.4.

digitalSourceType

1. Rule 1 labels composites as fully AI-generated. Rule 1 looks for c2pa.created + trainedAlgorithmicMedia anywhere in the ingredient chain. Take a camera photo with an AI-generated element placed into it (c2pa.placed, componentOf ingredient). That element’s own manifest has c2pa.created + trainedAlgorithmicMedia, so Rule 1 fires and the photo is labelled AI-generated. Rule 2 would have given the correct compositeWithTrainedAlgorithmicMedia. A manifest has at most one c2pa.created/c2pa.opened (§18.15). So Rules 1 and 3 should follow only the parentOf chain from the active manifest down to its root c2pa.created. componentOf and inputTo ingredients should feed only Rule 2. Ingredients removed with c2pa.deleted should probably be skipped.

2. Rule 3 can produce values that aren’t IPTC terms. C2PA allows its own values alongside IPTC ones: http://c2pa.org/digitalsourcetype/empty and http://c2pa.org/digitalsourcetype/trainedAlgorithmicData (§18.15.4.5). empty is required for anything started from a blank canvas or template, so Rule 3 will often return it. The FEP should either allow these values or say to leave the property out.

3. Ingredients without a manifest can carry their own digitalSourceType. When an ingredient has no active manifest, the ingredient assertion may have a digitalSourceType field (§18.16.11). The rules only look at actions, so they miss these.

4. Please define “AI source type”. At minimum, list trainedAlgorithmicMedia, compositeWithTrainedAlgorithmicMedia, compositeSynthetic and C2PA’s trainedAlgorithmicData. Also say whether algorithmicMedia and algorithmicallyEnhanced count.

5. Only the AI label is protected. The FEP keeps receivers from dropping an AI label, but says nothing about how much to trust digitalCapture. “This is a real photo” is the label people have a reason to fake. I’d suggest receivers SHOULD NOT present a non-AI source type as verified unless the publisher reports Valid or Trusted.

contentCredentials

6. The validationState values don’t match C2PA. §14.3 defines three manifest states: Well-Formed, Valid and Trusted. There is no “Invalid”. Well-Formed (structurally fine, but the signature isn’t valid, for example because the certificate expired or was revoked) is missing, and it’s a common result in practice. C2PA also separates manifest state from asset state (§14.3.3): a manifest can be Valid while the file’s content hash no longer matches. I’d suggest the three C2PA terms plus an explicit “no valid manifest” value, or carrying the C2PA status codes.

7. signer should come from the certificate subject, not the issuer. The issuer is the certificate authority, so as written most attachments would show the CA’s name rather than “Example Labs” (§14.2).

8. claimGenerator source field. v2 claims use claim_generator_info, a map with name and version (§10.2.3). v1 claims use a claim_generator string. Worth saying which field to read for each.

9. The summary describes a different file from url. (This is the same gap @mczachurski describes.) contentCredentials describes the original upload, but url serves the re-encoded copy. Unless that copy is signed, a receiver can’t check the claim. Two possible fixes: include the original active manifest’s label (its URN) so receivers can match things up, and mention the sidecar/Link option described above.

Signed derivatives

10. Use c2pa.transcoded for server resizing, not c2pa.resized. c2pa.transcoded explicitly covers resolution scaling and is a non-editorial transformation. c2pa.resized isn’t classed as non-editorial in 2.4, and the 2.5 draft classes it as perceptible. An actions list containing only c2pa.published, c2pa.transcoded and c2pa.repackaged tells consumers that nothing editorial changed (§18.15), which is exactly what a federating server wants to say. c2pa.resized.proportional (non-editorial) is another option.

11. Spell out the manifest structure. The first action needs to be c2pa.opened, referencing a c2pa.ingredient.v3 assertion with relationship: parentOf (§18.16.3). It would also help to say:

  • Personal data has to be removed before signing, not after.
  • The JUMBF/APP11 data has to survive any later pipeline step, such as a CDN or image optimizer.
  • A server certificate that isn’t on the C2PA Trust List gets Valid, not Trusted.

12. The redaction list.

  • stds.exif has been deprecated since 2.0. It still shows up in older manifests, so keep it, but it isn’t the main risk.
  • The parent manifest’s thumbnail (c2pa.thumbnail.claim.* / c2pa.thumbnail.ingredient.*) is the biggest leak. In the “then cropped” example, it would show the uncropped original.
  • Also worth listing: custom *.metadata assertions (any namespace is allowed), identity assertions, and stds.schema-org.CreativeWork (author).
  • It may help to describe how redaction works (§6.8): the assertion is removed and listed in the new claim’s redacted_assertions, and adding a c2pa.redacted action is strongly recommended. c2pa.actions can never be redacted, so the provenance history always survives.
  • For the “can’t redact” fallback: partial redaction, for example keeping camera info and dropping location, is possible through an update manifest (§18.17.4).

Minor

  • C2PA 2.5 is in progress, so it’s worth citing sections by anchor as well as number.
  • “A publisher MUST only include…” may read more clearly as “A publisher MUST NOT include contentCredentials unless it validated the manifest itself.”

I’m happy to help with wording on any of these.