ChatGPT PDF Content Credentials: what survives a re-save, a print and an edit
We asked ChatGPT to change the date on an invoice it had generated. It did, and the new file still carries OpenAI's signed statement that ChatGPT created it: the same manifest, byte for byte, describing the version with the old date.
That invoice was one of ten invented documents we generated to measure what this mark tells you and what is left of it after a re-save, a print or a screenshot. OpenAI publicly documents provenance signals for images and audio (C2PA and SynthID for images, SynthID for audio), but its public verification API does not accept PDFs.
| Step | C2PA manifest | What we observed |
|---|---|---|
| Original PDF | Present | Signature and hash validate |
| qpdf rewrite | Kept | Stream compressed; c2pa-python 0.38 reports an error |
| pikepdf rewrite | Kept | Same error |
| Print or Preview re-render | Removed | Text layer kept |
| Rasterised | Removed | Text layer and PDF structure gone |
| Invoice edited by ChatGPT | Kept | The old manifest no longer matches the file |
Observed in these files; other PDFs may behave differently.
What the mark is
The C2PA specification stores the manifest in a PDF as an embedded file, which the document catalog points to through its /AF entry.
trainedAlgorithmicMedia is the IPTC term for "created by a trained model". This is not a /Creator string anyone can type; it is a signed statement by the tool. A cryptographic signature makes an altered claim detectable. But a signed manifest can be copied into another PDF without becoming valid for that document, which is why the hash matters.
An untouched file validates
Read with c2pa-python 0.38, the official reader, a freshly downloaded file comes back Valid with assertion.dataHash.match: these are the bytes the manifest describes. The reader calls the certificate untrusted because we loaded no trust list. A valid signature and a matching hash do not by themselves establish a trusted signer: trust requires a recognized certificate chain and a trust policy.
A file in the public veraPDF test corpus also carries a genuine OpenAI manifest, but comes back Invalid with assertion.dataHash.mismatch. Its Producer is the corpus's own builder and its modification date is fourteen minutes after the signature: the file was rewritten around the manifest.
Finding the manifest says a tool once made a document. Validating it says whether the tool made this one.
Two PDF revisions, and no visible metadata
In these files ChatGPT built the PDF with ReportLab, then appended the manifest as an incremental update.
So a revision counter sees two revisions on a file nobody edited; here the second one is the signing. And the appended trailer has no /Info entry, so pdfinfo and pikepdf report no metadata at all, although the first revision's Info is still in the bytes.
Ten files, one shape
Two versions of a bank statement, an invoice, a receipt, a payslip, a resume, a letter, a report and an image on a PDF page: these nine untouched files all have this shape and all validate. The tenth is the edited invoice below. All ten come from one account over two days, so they are specimens, not a survey of ChatGPT's behaviour.
In most of them the hidden Info says only "anonymous" or "ReportLab", so the manifest is the one thing that names the tool.
When we asked for a generated image as a PDF, the image's own manifest (gpt-image) did not travel. ChatGPT signed the PDF separately, as the chat model.
What survives a rewrite, a print and a screenshot
We put each file through each transformation and read every result three ways: a search of the raw bytes for "ChatGPT", c2pa-python, and a reader that decodes the embedded stream first. The macOS steps call the system APIs behind Print and Preview directly.
After a rewrite by qpdf or pikepdf, the mark survives and two of the three readers miss it. Both tools compress streams that were stored raw, so "ChatGPT" disappears from the raw bytes, and c2pa-python 0.38 failed on these files with "invalid JUMBF header", because it read the stream without decoding it. In our tests one qpdf pass hid the mark from both without removing it. The remedy is to decode the stream through a PDF parser before looking.
This is separate from a problem the PDF Association has described in ChatGPT PDFs, a stray /F entry in the embedded stream that makes the credentials unusable. Our ten files do not have that entry.
In our runs a page re-render through Print or Preview dropped the embedded file and kept the text layer. Rasterising removes the PDF's text layer, fonts, attachments and manifest. The resulting image may carry its own metadata or provenance signals, but those are separate from the PDF's credentials. A paper scan or a phone photo is the same case.
When ChatGPT edits its own PDF
We uploaded the invoice back into a chat and asked for the date to be changed to 15 October 2026.
The file was rewritten and the old manifest came along: same SHA-256, no new claim, no new signature. It still says "created by ChatGPT" under a genuine OpenAI signature, about bytes that no longer exist. A tool that only looks for the mark sees what it saw on the original, and the official reader cannot open the file at all. Only comparing the manifest's hash with the file's bytes shows that the document changed after signing. One edit, one file: this is what ChatGPT did here, not necessarily what it always does.
What this means for a document check
Our approach: on an issued document, the mark is a red flag. Bank statements, receipts, payslips and diplomas come from the issuer's own systems, not from a chat assistant, so we treat one that carries an AI mark as not issued by the institution it names until that institution confirms otherwise. On a letter or a resume, the mark only tells you which tool was used. We regularly see such documents among the files sent to us for checking, and those are only the ones that still carry the mark.
Validate, then trust. Act on the validation state, with a trust list loaded. A failed hash alone does not say whether the document was rewritten or the manifest transplanted.
Absence proves nothing. The mark catches whoever did not know it was there. A print or a screenshot removed it in every test, with no intent required; when you receive a picture, ask for the original PDF.
Check the numbers too. In the GPT4o-Receipt study of 1,235 receipts, the main tell was arithmetic: line items that do not sum, tax that does not match. That check survives every transformation above.
What our check does with the mark
Finding the mark is a forensic signal, not confirmed attribution. Our report reads the same mark and decodes streams, so it reports ChatGPT on the original and the rewritten copies and nothing on the re-rendered and rasterised ones. It does not check the signature or the hash: a transplanted manifest and the edited invoice read the same as the original, and the report calls the finding a marker, not proof. A file without a mark gets no finding from this check. Details and limits: AI-generated document fraud.
Content Credentials are one part of document forensics, not a complete fraud check. A bank statement can carry no AI mark and still show text laid over the original, inconsistent fonts or a balance that does not add up. Our report looks for those signs as well.
Reproduce it
The ten files, their checksums and the reader script are public at github.com/atomara-io/chatgpt-pdf-provenance.