What a signature actually covers

Three signal families on digital signatures: how much of the file the signature covers, whether what was signed is still what is there, and what the signer allowed to change afterwards.

A signed PDF is not the same as an unmodified one. A signature covers a defined range of bytes, and everything appended after that range is outside it — legitimately, because that is how the format was designed. These three families report the distance between “this document is signed” and “this document is what was signed”.

Part of the field guide — three of the eighteen families the engine reports.

Signals, not verdicts. Every finding here is a structural fact about a file. "This document was modified after generation" is true or false about the bytes; "this document is fraudulent" is a judgement about a person, and Tamperlens does not make it. The API returns no boolean verdict field, by design.

signature-coverage

info high
What it detects
Whether each signature's /ByteRange actually covers the whole file. /ByteRange is an array of offset/length pairs naming exactly which bytes a signature protects — normally everything except the hole where the signature value itself sits. Tamperlens computes the highest covered offset and compares it with the file length. Anything beyond it was appended after signing and is not protected by that signature.
This is the strongest structural finding in the engine, and it is arithmetic rather than cryptography: two integers, no certificate needed, no trust store consulted. It holds regardless of whether the signature's mathematics validate — which is exactly why it is worth reporting separately from validation.
Evidence returned
Per signature: object number, /SubFilter, the raw /ByteRange array, coveredEnd, bytesAfterCoverage, coversWholeFile, and the total file size. Plus uncoveredCount and the document's revision count.
Benign causes
The mechanism itself is a normal and intended part of PDF: a second signer, or a legitimate incremental save such as adding a permitted annotation to an already-signed document, produces bytes outside the first signature's range. PDF has a whole concept — DocMDP permissions — for expressing which subsequent changes a signer allowed. Tamperlens reports the coverage gap; it does not evaluate whether the change was permitted. Multi-signature workflows will therefore fire this legitimately.
Two things this family explicitly does not do: verify signature cryptography, and validate the signing certificate or its trust chain. Those are separate jobs and a coverage report is not a substitute for either.
Severity logic
No signature fields: silent. high when at least one signature has a parsed /ByteRange that does not reach the end of the file. info when the document is signed and every signature spans the entire file — reported deliberately, as a positive fact worth having in the report rather than silence.

signature-integrity

high low
What it detects
Whether the bytes a signature covers still produce the digest that signature committed to. This is the companion to signature-coverage, and the pair only makes sense together: coverage asks whether anything was added outside the signed range, and this asks whether anything changed inside it. A document can pass either and fail the other.
The difference matters because their innocent explanations are not comparable. Bytes appended after a signature are completely normal — a second signer, an added annotation, a filled form field all do it. A digest mismatch is not: a correctly-produced signed PDF cannot have one. Something inside the protected region was changed after it was protected.
It is arithmetic over the file's own bytes. The signature's /ByteRange names the spans it covers; those spans are hashed and compared with the messageDigest attribute inside the PKCS#7 blob. No network request is made and no clock is read, so the same file gives the same answer forever.
Evidence returned
signatures, verified, mismatched and unreadable as counts, then findings with each signature's status, its digest algorithm, and — where they differ — the leading bytes of both expectedDigest and actualDigest, so the claim can be checked rather than taken on trust.
Benign causes
For a mismatch, essentially none — which is why it is the rare finding reported at high on its own. For an unreadable result there are many, and it is reported at low precisely because it is not an accusation: the signature simply is not in a form this engine reads.
What it cannot see
This is not certificate validation, and a verified digest is not a statement that the document is trustworthy. Tamperlens does not examine who signed, does not walk the certificate chain to a trusted root, and does not check whether that certificate was revoked. A mathematically intact signature by a completely unknown signer reads exactly the same here as one from a bank.
Only detached PKCS#7 signatures (adbe.pkcs7.detached, ETSI.CAdES.detached) are checked. adbe.pkcs7.sha1 is deliberately declined rather than approximated — it stores its digest differently, and checking it the same way would report a mismatch on a perfectly good signature.
Severity logic
high when covered bytes do not produce the committed digest. low when a signature is present but could not be checked — reported rather than omitted, because silence would read the same as "checked and fine". A verified digest is reported as info and contributes nothing to the risk score.

signature-permissions

high medium low
What it detects
Whether the document changed in a way its own signature said it must not. This is the third of the signature families and the one that makes the first usable: signature-coverage reports that bytes were appended after signing and then has to list the innocent explanations, because it cannot tell them apart. A certification signature already answered that question at signing time.
When a document is certified, the signer writes a permission level into it — /DocMDP /P. 1 permits no changes at all; 2 permits filling in form fields and adding further signatures; 3 additionally permits annotations. This family compares that number against what the revisions written afterwards actually touched.
Most signed PDFs are not certified. An ordinary approval signature attests to the document as it stood and declares nothing about what may follow — and that is itself reported, because "the signature covers the whole file" reads to most people as "verified" when it only means the signature's extent, not anyone's permission.
Evidence returned
docMDPPermission (and whether it was docMDPPermissionDefaulted), permsTarget, appendedRevisions, and a touched breakdown counting how many page content streams, images, page-reachable images, pages, form widgets, other annotations and signature objects the later revisions wrote — images and pageImages are reported separately, so 3 and 0 tells you pictures arrived and none of them landed on a page — plus changedObjectSample, the object numbers behind the finding, so it can be checked in the file.
Benign causes
Filling in a form regenerates appearance streams, which look like content streams and are not. Only objects reached from a page's /Contents count here, which is what keeps a permitted form fill-in from reading as a violation.
A visible signature carries a picture. The rendered signature block, an institutional mark, a scanned rubric — these live in the signature widget's appearance stream, not on the page, and adding a signature is exactly what /P 2 permits. Only images that a page's resources name are counted. Measured across the corpus, 109 of 320 revisions that added a signature carry such an image and no page content at all; before engine 1.24.0 every one of them would have been reported as a violation.
Long-term validation data. Adding the certificates and revocation responses that let a signature be checked years later appends a revision even to a document certified /P 1. It is routine, it is what ICP-Brasil's Referência de Tempo policy produces, and a document whose catalog carries a /DSS store gets it reported as info rather than as a change.
What it cannot see
/P is a number in a dictionary, and this family makes no trust decision whatsoever. It does not check who certified the document, whether their certificate chains to a trusted root, or whether the signature validates at all — that last question belongs to signature-integrity. A permission declared by an unknown signer reads exactly the same here as one from a government issuer.
It cannot say what a change was for. It reports that a page content stream was rewritten after a certification that did not permit it, not what the new page says.
It compares against the certification and against nothing else. In a document with several signatures, a change made after an earlier signer signed but before the document was certified was part of what got certified, and is invisible here — that is a per-signature question, answered separately by signature-coverage and signature-integrity.
A /P 3 document can be changed visibly without any permission being violated. /P 3 permits annotations, and an annotation carries arbitrary visible content in its appearance stream. The spec-correct answer and the answer a reader wants are not the same at /P 3, and no reading of /DocMDP alone closes that gap.
Severity logic
high when a page content stream, or an image one of the document's pages names, was written after certification — no permission level allows the page to be repainted — or when anything at all was altered under /P 1. high also when the catalog names a certification signature that carries no certification, which is what stripping one leaves behind.
medium when a non-form annotation appears under /P 2. low when bytes were appended to a /P 1 document but touched only signature and bookkeeping objects with no /DSS to explain them — a "look at this", not an accusation. Everything else is info and contributes nothing to the risk score: an uncertified document, and a signature declaring a certification the catalog never adopted. That second one was medium for about an hour — measured against 915 real documents it fired 5 times and was wrong 5 times, every one a government contract whose producer writes the transform and omits the catalog entry. See docs/CORPUS-PHASE0-PERMISSIONS-2026-08-05.md.

See the report on your own file

The free checker runs every family on this page and renders the full evidence — no account, nothing stored. To run it in your own pipeline, see the API quickstart or create an account for a key with 50 free documents a month.

Tamperlens reports risk signals, not authenticity verdicts. Signals can have benign causes; combine them with your own decision logic.

The rest of the guide