[
https://issues.apache.org/jira/browse/PDFBOX-6236?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18106114#comment-18106114
]
Tilman Hausherr edited comment on PDFBOX-6236 at 8/20/26 8:33 AM:
------------------------------------------------------------------
yes there are gaps... this was previously discussed in PDFBOX-5382 but never
resolved.
20.08.2026 05:41:47 WARN signature.SigUtils.checkCrossReferenceTable:468 -
Object 15 missing, signature verification may fail in Adobe Reader, see
https://stackoverflow.com/questions/71267471/
20.08.2026 05:41:47 WARN signature.SigUtils.checkCrossReferenceTable:468 -
Object 21 missing, signature verification may fail in Adobe Reader, see
https://stackoverflow.com/questions/71267471/
20.08.2026 05:41:47 WARN signature.SigUtils.checkCrossReferenceTable:468 -
Object 32 missing, signature verification may fail in Adobe Reader, see
https://stackoverflow.com/questions/71267471/
Coincidentally, the original file has 14 objects shown in PDFDebugger.
was (Author: tilman):
yes there are gaps... this was previously discussed in PDFBOX-5382 but never
resolved.
20.08.2026 05:41:47 WARN signature.SigUtils.checkCrossReferenceTable:468 -
Object 15 missing, signature verification may fail in Adobe Reader, see
https://stackoverflow.com/questions/71267471/
20.08.2026 05:41:47 WARN signature.SigUtils.checkCrossReferenceTable:468 -
Object 21 missing, signature verification may fail in Adobe Reader, see
https://stackoverflow.com/questions/71267471/
20.08.2026 05:41:47 WARN signature.SigUtils.checkCrossReferenceTable:468 -
Object 32 missing, signature verification may fail in Adobe Reader, see
https://stackoverflow.com/questions/71267471/
> PDDocument.saveIncremental() adds a new field object whose number collides
> with the increment's own XRef stream object, on a PDF that already contains a
> prior signature
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: PDFBOX-6236
> URL: https://issues.apache.org/jira/browse/PDFBOX-6236
> Project: PDFBox
> Issue Type: Bug
> Affects Versions: 3.0.6 PDFBox
> Environment: - Java 25 (Eclipse Temurin 25+36)
> - OS: Linux
> Reporter: Riadh
> Priority: Major
> Attachments: PDFBOX-BUG-REPORT.md, ReproPdfBoxOnly.java,
> already-signed.pdf, with-empty-field.pdf
>
>
> ## Summary
> Adding a new AcroForm field (a `PDSignatureField`, but the field type does
> not appear to matter) to a PDF that already contains one prior signature,
> then saving it with `PDDocument#saveIncremental(OutputStream)`, produces a
> document in which the new field's indirect object number is ambiguous:
> PDFBox's own reader resolves it to the expected field dictionary, but any
> reader that builds a flat cross-reference map across the full `/Prev`
> revision chain (e.g. pypdf, PyPDF2 — tested with both, same result) resolves
> the very same object number to the incremental update's own `/XRef` stream
> dictionary instead. No signing is actually performed in this reproduction —
> this is a pure `saveIncremental()` issue, independent of any
> digital-signature or third-party library (e.g. it does **not** require the EU
> DSS library; the attached reproduction uses only `org.apache.pdfbox.*`
> classes).
> ## Steps to reproduce
> 1. Start from any PDF that already has one prior signature (any signature
> type/level). In the attached `already-signed.pdf`, the highest existing
> object number is 42 (`COSDocument#getHighestXRefObjectNumber() == 42`), the
> AcroForm has 2 fields: a `/Sig` field at object 9 and a text field at object
> 10. 2. Add a new signature field and save incrementally:
> {code:java}
> try (PDDocument doc = Loader.loadPDF(new File("already-signed.pdf"))) {
> PDAcroForm acroForm = doc.getDocumentCatalog().getAcroForm();
> PDPage page = doc.getPage(0);
> PDSignatureField signatureField = new PDSignatureField(acroForm);
> signatureField.setPartialName("signature_signed_pdfbox_only");
> PDAnnotationWidget widget = signatureField.getWidgets().get(0);
> widget.setRectangle(new PDRectangle(50, 50, 100, 50));
> widget.setPage(page);
> page.getAnnotations().add(widget);
> acroForm.getFields().add(signatureField);
> try (FileOutputStream fos = new FileOutputStream("with-empty-field.pdf"))
> {
> doc.saveIncremental(fos);
> }
> } {code}
> (Full source in the attached `ReproPdfBoxOnly.java`.)
> 3. Inspect the resulting `with-empty-field.pdf`.
> ## Expected result
> The AcroForm's `/Fields` array has 3 entries, and the new entry (object
> number 43 in this reproduction) resolves — consistently, from any conformant
> PDF reader — to the new field's `/Widget` dictionary.
> ## Actual result
> - Re-opening the file **with PDFBox itself** resolves object `43 0 R`
> correctly:
> {code:java}
> field[2] objNum=43 /Type=Annot /FT=Sig /T=signature_signed_pdfbox_only
> hasV=false {code}
> - Reading the **same file** with `pypdf` (6.16.1) or `PyPDF2` (both tested,
> identical result) resolves the very same reference (`43 0 R`) in the
> AcroForm's `/Fields` array to the increment's own `/XRef` stream dictionary
> instead:
> {code:java}
> >>> fields[2].get_object()
> {'/ID': [...], '/Info': ..., '/Root': ..., '/Prev': 55240, '/Type': '/XRef',
> '/Size': 44, '/Index': [0, 2, 33, 10], '/W': [1, 3, 0], '/Filter':
> '/FlateDecode'}
> >>> pdf.get_fields().keys()
> dict_keys(['signature', 'prénom']) # the new field is invisible {code}
> Object number `43` is therefore used ambiguously within the same incremental
> update: PDFBox's writer appears to reuse/collide the number allocated to the
> new field object with the number allocated to the revision's own `/XRef`
> stream object. Since a standards-compliant reader merging the `/Prev` xref
> chain keeps only the *last* xref entry seen per object number, and PDFBox
> itself resolves it one way while other libraries resolve it the other way,
> this indicates PDFBox's `COSWriter` writes conflicting/duplicate xref
> information for object `43` within this single incremental revision.
>
> ## Suggested area to investigate
> `org.apache.pdfbox.pdfwriter.COSWriter`:
> - The `number` counter used both to allocate new object keys while writing
> the body (`getObjectKey(COSBase)`) and to allocate the xref-stream's own key
> in `doWriteXRefInc()` (`COSObjectKey xrefStreamKey = new
> COSObjectKey(++number, 0)`).
> - This counter is seeded from `COSDocument#getHighestXRefObjectNumber()`,
> itself computed by `COSParser` by merging the `/Prev` xref chain at load time
> (`org/apache/pdfbox/pdfparser/COSParser.java`, around the code that does
> `document.setHighestXRefObjectNumber(...)` after building
> `document.getXrefTable()`).
> - When the input document already has objects from a prior
> signature/incremental revision, this next-object-number computation appears
> not to always fully account for the existing revision chain, so the number
> handed out for the new field object collides with the number subsequently
> used (or already used) for the increment's own xref-stream object.
> This looks adjacent to — but distinct from — PDFBOX-4997 (unmodified
> `COSName`-only objects being needlessly rewritten during incremental
> updates), which was found while investigating this issue but does not by
> itself explain the object-number collision described here.
> ## Impact
> Any workflow that adds a new form/signature field to a PDF that already
> carries a prior signature, then saves incrementally (a common pattern for
> sequential multi-signer PAdES workflows, e.g. via the EU DSS library's
> `PAdESService#addNewSignatureField`, which is how we first found this)
> produces a PDF where the newly added field is not reliably discoverable by
> other PDF libraries, even though PDFBox's own reader can still find it — a
> real interoperability/validation risk for any consumer not using this exact
> PDFBox version and reading strategy.
> ## Attachments
> - `already-signed.pdf` — input document with 1 existing signature.
> - `with-empty-field.pdf` — output of the reproduction, already exhibiting the
> corrupted `/Fields` entry.
> - `ReproPdfBoxOnly.java` — full minimal reproduction source (pure PDFBox, no
> external dependency beyond PDFBox itself).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]