Release note · August 6, 2026

A signature range needs a current file boundary

By SybilGambleyyu · PDFFence 1.17.0

A PDF review can see a signature dictionary and still miss an important boundary question: does its stored /ByteRange still end at the physical end of the file being reviewed? An incremental update can leave an earlier range structurally intact while appending a later revision. That is not, by itself, a verdict about whether the signature is valid or whether the update is allowed. It is useful static evidence that should be visible to a reviewer.

A signature needs a document owner too

PDFFence 1.17.0 does not treat every reachable /Type /Sig dictionary as a signature. It establishes a signature root only through a catalog-reachable AcroForm signature field, including inherited /FT, or through a catalog /Perms DocMDP, UR, or UR3 entry. A private producer dictionary beneath /PieceInfo can still affect generic stored-byte or reachability evidence, but it cannot manufacture signature inventory evidence merely by resembling a signature.

That semantic-owner boundary follows the same principle that matters elsewhere in a PDF: familiar keys acquire meaning from the standard structure that owns them, not just from their local spelling.

Current-file boundary, not signature validation

For a semantic root, PDFFence reports only aggregate counts: signature dictionaries, ByteRange presence, well-formed layouts, and ByteRanges whose final endpoint reaches the current physical file end. A layout must use direct integer pairs, start at byte zero, have non-negative offsets and positive lengths, remain ordered and in bounds, and end at the current file boundary to contribute to the last count. No offsets, /Contents, certificate material, digest, transform, or trust result is exposed.

The PDF 2.0 signature errata describe the expected ByteRange boundary for a signature's incremental revision. The PDF Association advisory on digital-signature vulnerabilities is equally important context: a boundary check is not a substitute for a conforming signature validator.

A targeted review gate

The new opt-in no_signature_coverage_regressions policy rule, PFP009, fails only when the aggregate number of semantic ByteRanges reaching the current file end falls. In the new positive control, a valid field-root ByteRange reaches the original file end; a valid incremental update leaves that same range behind the new end. Signature structure stays fixed, while the generic coverage change and PFP009 make the boundary loss review-visible.

The companion PDF Change Assurance Benchmark 1.17.0 also adds the inverse control: a private PieceInfo signature-shaped dictionary is added with no form-field or catalog-permission owner. Its expected result is reachability plus stored-byte evidence only. The released 1.16.0 wheel misses the coverage event in the first control and creates a false signature-structure event in the second; 1.17.0 scores all 154 pairs.

Validation and scope

PDFFence passed 233 tests and Ruff; PDFCAB passed 84 tests and Ruff. Two fixed-timestamp builds of each package were byte-for-byte reproducible and passed Twine metadata checks. Clean paired wheel installs on Python 3.12 and 3.13, plus a clean paired Python 3.12 source-archive install, passed dependency checks, fixture verification, and the complete 154-pair score.

This is deliberately static boundary evidence. PDFFence does not locate or validate signature contents, calculate a signed digest, validate certificates or trust chains, inspect transforms or permissions, render a document, or conclude that any update is safe, permitted, or authentic. The tagged policy reference, threat model, and validation record define the supported boundary.

python -m pip install https://github.com/SybilGambleyyu/pdffence/releases/download/v1.17.0/pdffence-1.17.0-py3-none-any.whl

pdffence init pdffence.yml
pdffence check before.pdf after.pdf --policy pdffence.yml --format sarif

PDFFence is MIT-licensed and available on GitHub. The release assets include SHA-256 checksums for the wheel and source archive.