PdfReader throws an uncaught NullPointerException (instead of a proper InvalidPdfException,
or simply treating the document as unencrypted) when the trailer's /Encrypt entry is an
indirect reference to an object number that does not exist / has no entry in the xref table.
Root cause, in readDecryptedDocObj():
PdfObject encDic = trailer.get(PdfName.ENCRYPT);
if (encDic == null || encDic.toString().equals("null")) {
return;
}
encryptionError = true;
byte[] encryptionKey = null;
encrypted = true;
PdfDictionary enc = (PdfDictionary) getPdfObject(encDic); // PdfReader.java:1424 — can return null
...
PdfObject filter = getPdfObjectRelease(enc.get(PdfName.FILTER)); // PdfReader.java:1449 — NPE
getPdfObject(encDic) resolves the indirect reference through the xref table and returns null
when the referenced object number has no xref entry (malformed/non-conformant producer). enc is
never null-checked before being dereferenced on the next line.
Other tools (poppler's pdfinfo, qpdf) open the same kind of malformed file without error and
correctly report it as not encrypted — the dangling /Encrypt reference is simply ignored.
OpenPDF is the only reader in our pipeline that crashes on this class of file.
To Reproduce
- Sample Code — minimal malformed PDF (
/Size 5, but object 4 referenced by /Encrypt has no
real xref entry):
%PDF-1.4
1 0 obj
<< /Type /Catalog /Pages 2 0 R >>
endobj
2 0 obj
<< /Type /Pages /Kids [3 0 R] /Count 1 >>
endobj
3 0 obj
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] >>
endobj
xref
0 5
0000000000 65535 f
0000000009 00000 n
0000000058 00000 n
0000000115 00000 n
0000000000 00000 f
trailer
<< /Size 5 /Root 1 0 R /Encrypt 4 0 R >>
startxref
186
%%EOF
- Unit-Test:
import org.openpdf.text.pdf.PdfReader;
import org.openpdf.text.pdf.RandomAccessFileOrArray;
public class TestReproPartial {
public static void main(String[] args) throws Exception {
var raf = new RandomAccessFileOrArray("malformed_encrypt.pdf");
PdfReader r = new PdfReader(raf, new byte[0]); // partial-read path
System.out.println("Opened OK, encrypted=" + r.isEncrypted());
}
}
Output (verified against openpdf-3.0.3.jar):
java.lang.NullPointerException: Cannot invoke "org.openpdf.text.pdf.PdfDictionary.get(org.openpdf.text.pdf.PdfName)" because "enc" is null
at org.openpdf.text.pdf.PdfReader.readDecryptedDocObj(PdfReader.java:1449)
at org.openpdf.text.pdf.PdfReader.readDocObjPartial(PdfReader.java:1796)
at org.openpdf.text.pdf.PdfReader.readPdfPartial(PdfReader.java:1387)
at org.openpdf.text.pdf.PdfReader.<init>(PdfReader.java:285)
Note: the simpler new PdfReader("malformed_encrypt.pdf") constructor (non-partial path) also
fails, but wraps the same NullPointerException into an InvalidPdfException at
PdfReader.readPdf(PdfReader.java:1348) — so the bug is reachable either way, just surfaced
differently depending on which constructor is used.
Expected behavior
PdfReader should not throw a bare NullPointerException. It should either:
- treat the document as unencrypted when the
/Encrypt dictionary can't be resolved (matching
poppler/qpdf behavior), or
- throw a descriptive
InvalidPdfException explaining that the encryption dictionary reference
is broken.
System
- OS: Linux (server-side; issue is not OS-specific, reproduced on the reader/parser)
- OpenPDF version: 3.0.3
Additional context
Found while processing real-world PDFs generated by a non-standard/home-grown producer
(Creator: PDFGen versão 0.1 beta), consistent with a hand-rolled trailer containing a stray
/Encrypt N 0 R reference to an object number beyond what's actually defined. The minimal PDF
above reproduces the exact same code path and line numbers as the original crash, without
exposing any real document content.
PdfReaderthrows an uncaughtNullPointerException(instead of a properInvalidPdfException,or simply treating the document as unencrypted) when the trailer's
/Encryptentry is anindirect reference to an object number that does not exist / has no entry in the xref table.
Root cause, in
readDecryptedDocObj():getPdfObject(encDic)resolves the indirect reference through the xref table and returnsnullwhen the referenced object number has no xref entry (malformed/non-conformant producer).
encisnever null-checked before being dereferenced on the next line.
Other tools (poppler's
pdfinfo,qpdf) open the same kind of malformed file without error andcorrectly report it as not encrypted — the dangling
/Encryptreference is simply ignored.OpenPDF is the only reader in our pipeline that crashes on this class of file.
To Reproduce
/Size 5, but object4referenced by/Encrypthas noreal xref entry):
Output (verified against
openpdf-3.0.3.jar):Note: the simpler
new PdfReader("malformed_encrypt.pdf")constructor (non-partial path) alsofails, but wraps the same
NullPointerExceptioninto anInvalidPdfExceptionatPdfReader.readPdf(PdfReader.java:1348)— so the bug is reachable either way, just surfaceddifferently depending on which constructor is used.
Expected behavior
PdfReadershould not throw a bareNullPointerException. It should either:/Encryptdictionary can't be resolved (matchingpoppler/qpdf behavior), or
InvalidPdfExceptionexplaining that the encryption dictionary referenceis broken.
System
Additional context
Found while processing real-world PDFs generated by a non-standard/home-grown producer
(
Creator: PDFGen versão 0.1 beta), consistent with a hand-rolled trailer containing a stray/Encrypt N 0 Rreference to an object number beyond what's actually defined. The minimal PDFabove reproduces the exact same code path and line numbers as the original crash, without
exposing any real document content.