Read a C2PA manifest yourself: hashes, signer and edit history with c2patool
Tested onUbuntu 22.04, c2patool 0.28.4 built from source, 2026-10-30

To read a C2PA manifest, install c2patool and run c2patool followed by the file name. It prints the manifest as JSON. Look for four things there: the hash binding (c2pa.hash.data), the signer (signature_info), the edit history (the actions assertion) and the validation_state, which reads Valid, Trusted or Invalid.
A C2PA manifest is the signed record inside a file that carries its content credentials: a hash of the content, who signed it, and what was done to it. You can read every part of it with c2patool, the open-source command-line tool from the Content Authenticity Initiative. This guide shows the commands, real output from a run, and what each field means.
It belongs to our guides to checking images, documents and text. If you would rather not use a terminal, checking content credentials in a browser reads the same record with less detail. If you want the background first, how a content credential grew out of a plain checksum explains the hash binding this guide points to.
The examples use c2patool 0.28.4 and the sample image C.jpg from the c2patool repository.
What you need
- A file that may carry content credentials (JPEG, PNG, MP4, PDF and other common formats).
- c2patool 0.28 or later.
- A terminal. Output is JSON, so a JSON viewer or
jqhelps but is optional.
Install c2patool
The tool now lives in its own repository, contentauth/c2patool on GitHub. Releases up to v0.27.15 were published from the older c2pa-rs monorepo, so older guides may point there.
On a Mac, the project documents Homebrew:
brew install c2patool
On Windows or Linux, download the prebuilt archive for your system from the repository's releases page (the files end in x86_64-pc-windows-msvc.zip and x86_64-unknown-linux-gnu.tar.gz), unpack it and put c2patool on your PATH. On a system with no prebuilt archive, such as ARM64 Linux, build the same release from source with Rust's cargo install c2patool.
Check the install:
c2patool -V
c2patool 0.28.4
Read the manifest
Give c2patool the file name and nothing else. Per the c2patool usage documentation, it prints the manifest data as JSON to standard output.
c2patool C.jpg
The full output for the sample is about 5 KB. These are the parts that matter, in the order they appear (excerpt):
"claim_generator": "make_test_images/0.12.0 c2pa-rs/0.12.0",
"title": "C.jpg",
"format": "image/jpeg",
...
"label": "c2pa.actions.v2",
"data": {
"actions": [
{
"action": "c2pa.created"
},
{
"action": "c2pa.drawing",
"parameters": {
"name": "gradient"
}
}
]
}
...
"signature_info": {
"alg": "Ps256",
"issuer": "C2PA Test Signing Cert",
"common_name": "C2PA Signer",
"cert_serial_number": "720724073027128164015125666832722375746636448153",
"time": "2022-08-19T19:03:41+00:00"
},
...
"validation_state": "Valid"
For a quick summary instead of the JSON, add --info. The documentation says it reports the size of the manifest store, the number of manifests and whether the manifest validated:
c2patool C.jpg --info
Information for Provenance URI = self#jumbf=/c2pa/contentauth:urn:uuid:5a08e472-974c-422e-b38a-d6c7326481a5/c2pa.claim Manifest store size = 51167 (36.46% of file size 140346) Validation issues: signingCredential.untrusted One manifest
On this sample the manifest takes up just over a third of the file, because it carries a thumbnail.
Find the hash binding
The hash binding is what ties the manifest to these exact bytes. The default output summarises it as a passing check; the detailed report shows the value itself. Use -d:
c2patool C.jpg -d
Inside assertion_store, find c2pa.hash.data (excerpt):
"c2pa.hash.data": {
"exclusions": [
{
"start": 20,
"length": 51179
}
],
"name": "jumbf manifest",
"alg": "sha256",
"hash": "DcGR4k9M6aLXXCeDii4tSdX45rrIM5HSr1Wy/czQ6ro=",
"pad": "AAAAAAAAAAAA"
},
- alg: the hash algorithm, here SHA-256.
- hash: the digest, in Base64.
- exclusions: the byte range left out of the hash because the manifest itself sits there.
When you read the default output, the matching success codes are assertion.dataHash.match (the content hash matched) and assertion.hashedURI.match (each assertion matches the hash the claim recorded for it).
Find the signer and its certificate
signature_info names the signing certificate's issuer and common name, the signature algorithm and the signing time. On the sample, the issuer is "C2PA Test Signing Cert", which is why the manifest is not trusted. A credential from a camera maker or a news organisation would name that organisation here.
To inspect the certificate chain itself, the usage documentation describes --certs, which prints the PEM chain from the active manifest's signature:
c2patool C.jpg --certs
The signing time in our sample was also confirmed by a timestamp authority: the validation results include timeStamp.validated and timeStamp.trusted. A trusted timestamp shows when the claim was signed, independently of the signer's own clock.
Read the edit history (actions)
The actions assertion lists what the signing tool says happened to the file. The C2PA specification defines a fixed vocabulary (C2PA 2.5, actions). In the sample:
c2pa.createdmeans "the asset was first created or generated", whether by a person, a camera or an AI model. The specification requires a digital source type to be recorded with it, which is where an AI-generated file declares itself.c2pa.drawingmeans changes made "using drawing tools including brushes or eraser".
If a file was edited in several C2PA-aware tools, you will see more than one manifest. Each later manifest lists the earlier file as an ingredient, so the history reads as a chain. Remember that actions are statements by the signing software, so they are only as reliable as that software.
Read the validation status
validation_state is the summary. The specification defines a manifest as Well-Formed, Valid or Trusted (C2PA 2.5, validation states):
| Result | What it means | What it does not mean |
|---|---|---|
| Trusted | Valid, and the signing certificate chains to a trust list your tool uses | That the content is true |
| Valid | Unmodified since signing, the claim signature validates | That you know who the signer is |
| Invalid | Something failed: a hash, a signature, a structure | That the file is fake. Often it was simply re-saved |
| No manifest | Nothing to check | Anything about how the file was made |
Our sample read Valid with signingCredential.untrusted: intact and properly signed, but by a test certificate. That is exactly the gap between Valid and Trusted.
What a tampered file looks like
We flipped one bit in the image data and ran c2patool again. The summary now lists a second issue:
c2patool C-edited.jpg --info
Information for Provenance URI = self#jumbf=/c2pa/contentauth:urn:uuid:5a08e472-974c-422e-b38a-d6c7326481a5/c2pa.claim Manifest store size = 51167 (36.46% of file size 140346) Validation issues: signingCredential.untrusted assertion.dataHash.mismatch One manifest
The full JSON reported "validation_state": "Invalid" and the explanation "Hashes do not match". The signature over the manifest is still fine; it just describes different pixels.
What a stripped file looks like
Finally, we re-saved the sample with ImageMagick's -strip option, which removes metadata. c2patool found nothing:
c2patool C-stripped.jpg
Error: No claim found
--info on the same file printed No C2PA Manifests. (file size = 45470). A credential that has been stripped cannot be read back from that copy.
Save a copy of what you saw
A manifest on screen is easy to lose. If the result matters, keep a record you can show someone later. The usage documentation describes --output, which writes the manifest data, including thumbnails, to a folder:
c2patool C.jpg --output ./report
With -d, the same option saves the detailed report as detailed.json in that folder. Record the file's own SHA-256 next to the report, so anyone can confirm the report belongs to that exact file:
sha256sum C.jpg
5f57bc22ad54aab1228874e831a6feb5514e5875307945c4e4b11aae6c53e8b7 C.jpg
Note that this whole-file hash differs from the value in c2pa.hash.data. The manifest's hash leaves out the bytes where the manifest itself is stored; the whole-file hash includes them. Both are SHA-256.
Common problems
- "command not found" after installing: the folder holding
c2patoolis not on your PATH. Run it with its full path, or move it into a folder that is. - "No claim found" on a file you expected to carry credentials: the copy you have was re-saved or uploaded somewhere that stripped it. Ask for the original export.
signingCredential.untrustedon a file from a real organisation: your installation may have no trust list configured. The usage documentation describes thetrustsubcommand for loading one; until then, expect Valid rather than Trusted.- Several manifests listed: the file passed through more than one C2PA-aware tool. The
active_manifestfield names the newest; the others are its history. - Output too long to read: use
--infofor a summary, or save the JSON with--outputand open it in a viewer.
How to weigh what you found
On the evidence ladder, a trusted manifest with a matching hash is near the top: the bytes are unchanged and a known key vouched for them. A valid but untrusted manifest still proves the file is unchanged since signing, but you need another reason to trust the signer. An invalid manifest proves only that something changed. No manifest proves nothing, so move on to reading the file's EXIF, IPTC and XMP metadata, which is weaker evidence but often present.
Keep three limits in mind whatever the result. First, c2patool checks the record, and the record is a set of statements by the signing software: an action list or a digital source type is only as honest as the tool that wrote it. Second, a trust decision depends on the trust list your installation uses, so two people can see Valid and Trusted for the same file. Third, nothing in the manifest says whether the scene in the picture really happened. The manifest tells you which key stands behind the file and whether the file changed since; judging the content is still your job.
For a longer, plain-language tour of the standard itself, AFIP's C2PA and Content Credentials guide covers adoption and known limits.
Sources
Questions
What does "signingCredential.untrusted" mean?+
The signature checked out, but the signing certificate is not on the trust list c2patool used. The manifest can still be valid; it just cannot be attributed to a signer your tool recognises. Test images and many self-signed workflows show this code.
Why does c2patool say "No claim found" on a photo I know had credentials?+
The manifest has been removed, usually by a program that re-saved the file without it or by an upload service that strips metadata. Try to get an earlier copy of the file; the credential cannot be recovered from the stripped one.
Is c2patool the same thing as the browser verify tool?+
No, though both read the same C2PA manifests. c2patool shows the raw JSON, including the hash binding and every validation code, and lets you save it; the browser tool presents a summary.
Can c2patool add credentials as well as read them?+
Yes. It can sign and embed a manifest from a manifest definition file and a signing certificate. This guide covers reading only.
Which file types can c2patool read?+
The formats supported by the C2PA Rust library, including JPEG, PNG, WebP, HEIC, AVIF, TIFF, DNG, MP4, MOV, MP3, WAV and PDF. The library's supported-formats page keeps the full list.
Related reading
- How-to

Check content credentials
See who signed a file and what changed since
- Explainer

From checksums to content credentials
Start here: the fingerprint that links files and photos
- Explainer

Hash vs digital signature
Integrity of the file versus who stands behind it
- How-to

Check image metadata
Read what the camera wrote, and how easily it changes