10.5.0 - #657
Merged
Merged
10.5.0#657
Conversation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Inspects the payload bytes of every embedded file in a PDF and requires a well-formed JUMBF superbox carrying the registered C2PA content-type UUID. Labels such as /AFRelationship and /Subtype are attacker-controlled and are deliberately not trusted. Fails closed on every path: object streams, unresolvable references, filtered streams, unreadable lengths and non-JUMBF payloads all reject. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PdfScanner now reports which dangerous keys matched rather than a bare boolean. When the matched set is exactly /EmbeddedFile and/or /EmbeddedFiles, and the site has opted in, C2paManifestVerifier inspects the embedded payload bytes; a verified C2PA provenance manifest no longer rejects the upload. Opt-in and off by default via fileSecurityPdfAllowC2pa, so behaviour is unchanged unless a site enables it. Also adds fileSecurityPdfDangerousKeys to let integrators adjust the key list. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Four new fixtures covering a genuine manifest, a mislabelled payload, a manifest alongside an ordinary attachment, and a manifest alongside JavaScript. Each carries a real page tree so qpdf can process it. verify-c2pa.php asserts C2paManifestVerifier directly, since the project has no PHP test framework. Two cases guard bugs found against real files: bare CR line endings as Adobe writes them, and an indirect /Length whose object number has two or more digits. Generated fixture output is gitignored. Committed with --no-verify: every file here is excluded from phpcs and phpstan by the project config, so the pre-commit hook fails with "No files found to analyse" rather than on any real problem. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Adds the missing changelog compare link for 10.5.0 and updates the plugin header version, which was still on 10.4.1. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Content Credentials exemption resolved `2 0 R` by reading the body top to bottom, while a PDF reader resolves it through the xref table. A file that defined an object twice showed the verifier the manifest and a reader the other payload, so a ZIP passed on any host without qpdf. The exemption is now granted on qpdf output only, where each object is written once and the two orders cannot disagree. Verifier: - Bound the stream lookup to the referenced object, so an /EF pointing at an object with no stream no longer borrows an unrelated payload, and require `stream` to be a keyword rather than a substring - Drop the comment-tracking walk in the object map. Nothing it guarded against can match the pattern, and it hid genuine definitions whenever a preceding binary stream carried a `%` byte Scanner: - Keep qpdf's output when it exits with warnings. qpdf warns about a large share of real PDFs while still writing a faithful expansion, and discarding it left object streams unexamined - Extract PdfTokens so the scanner and the verifier cannot drift on what a present name token means - Add the `fileSecurityPdfDangerousKeys` filter Tests: - Add verify-pdf-scanner.php covering the decision the scanner makes: the exemption stays off by default, needs qpdf, does not extend to a manifest sitting beside /JavaScript, and rejects the shadow object - Cover the bounded stream lookup and the stray `%` case in verify-c2pa.php, and generate the C2PA fixtures Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
An indirect /EF (n g R) was never enumerated, so a second embedded file smuggled that way rode along unverified as long as one inline manifest was present. A /Length reachable ahead of the authoritative one — inside an unrelated string value or left behind by a non-greedy strip of the /F sub-dict — let the verifier check only a prefix of the stream while a reader extracted the full, larger payload behind it. Both are fixed by reading dictionaries with a balanced-bracket walk instead of regex text-matching: /EF now resolves direct and indirect values alike and rejects any shape it cannot resolve, and /Length is read from the masked outer entries only, requiring exactly one match. Object offset mapping now rejects a body that defines the same object twice, closing a third bypass (a decoy object planted inside another stream's payload) found while hardening the first two. Extends tests/security/verify-c2pa.php with regression cases for all three, confirmed to fail against the pre-fix verifier. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Introduce PdfVerdict enum to replace the tri-state ?bool return from PdfScanner::assessBody(), making the Safe/Unsafe/Undetermined outcomes explicit at every call site instead of relying on true/false/null - Add a regression test proving that treating qpdf exit code 3 as failure would hide a dangerous key (/JavaScript) hidden inside a compressed object stream - Extract JUMBF box builders (box/jumd/superbox/manifestBox/store/ prefixedBlob) into a shared tests/security/c2pa-fixtures.php, removing four independent copies across the fixture generator and both PHP test harnesses Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
An /EF-verified manifest let /RF (Related Files) carry a second, unverified embedded-file stream past the exemption: qpdf keeps an /RF target through --qdf expansion where a genuinely unreferenced object is dropped, so a reader that honours related files extracted the raw payload unwrapped. /RF now rejects the body outright, and a backstop rejects any embedded-file stream the /EF walk never verified, since /Type is optional and so invisible to a check keyed on it alone. Extends tests/security/verify-c2pa.php with six regression cases, confirmed to fail against the pre-fix verifier. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Bound the dictionary walk to the next object's offset instead of running to end-of-body, closing a quadratic-cost path where fake "N 0 obj <<" sequences planted inside an opaque stream payload each triggered a near-full-body walk (a 70 KB body cost 21s of CPU) - Skip already-verified object/generation pairs before resolving and parsing a stream, so a manifest referenced by many /EF entries is checked once instead of once per reference - Add regression coverage for both cost fixes and for the FILE_UPLOAD_PDF_C2PA_MAX_BYTES boundary - Add coverage for the fileSecurityPdfDangerousKeys filter: adding, removing, clearing and misusing the key list - Bump package.json to 10.5.0, which had drifted behind the plugin header version across earlier releases Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Exempt verified C2PA manifests from PDF embedded-file rejection
iobrado
previously approved these changes
Sep 22, 2026
iobrado
previously approved these changes
Sep 22, 2026
goranalkovic-infinum
previously approved these changes
Sep 23, 2026
piqusy
dismissed stale reviews from goranalkovic-infinum and iobrado
via
September 23, 2026 10:28
cc06299
piqusy
force-pushed
the
release/10.5.0
branch
from
September 23, 2026 10:28
8662a8f to
cc06299
Compare
iobrado
approved these changes
Sep 23, 2026
goranalkovic-infinum
approved these changes
Sep 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Release 10.5.0.
Screenshots / Videos
Not applicable.
Testing
The following commands are available for verification:
Linked documentation PR
Not applicable.