CVE-2026-59203 Overview
CVE-2026-59203 is an infinite loop vulnerability [CWE-835] in the Pillow Python imaging library. The flaw resides in the Encapsulated PostScript (EPS) parser located in PIL/EpsImagePlugin.py. Versions 12.0.0 through 12.2.0 accept a negative byte count in the %%BeginBinary: directive. A crafted EPS file causes Image.open() to seek backwards to the same directive and reparse it indefinitely. The Pillow maintainers fixed the issue in version 12.3.0.
Critical Impact
Any application that parses untrusted EPS files with vulnerable Pillow versions can be forced into an infinite loop, exhausting CPU resources and causing denial of service.
Affected Products
- Python Pillow 12.0.0
- Python Pillow 12.1.0 through 12.2.0
- Applications and services that call Image.open() on untrusted EPS input using affected Pillow versions
Discovery Timeline
- 2026-07-14 - CVE-2026-59203 published to NVD
- 2026-07-15 - Last updated in NVD database
Technical Details for CVE-2026-59203
Vulnerability Analysis
The vulnerability is a denial-of-service condition triggered during EPS image parsing. When Pillow encounters a %%BeginBinary: directive, it reads an integer byte count and calls self.fp.seek(bytecount, os.SEEK_CUR) to skip past the binary payload. The parser does not validate that bytecount is non-negative. A negative value causes the file pointer to move backwards, landing on or before the same %%BeginBinary: directive. The parser then re-reads the directive, seeks backwards again, and repeats this cycle without termination.
Because parsing occurs on Image.open(), exploitation does not require rendering or full decoding. Any workflow that opens EPS files, such as image processing pipelines, thumbnail generators, or document conversion services, is exposed. The result is 100% CPU consumption on the worker handling the file, blocking further requests and potentially cascading to service-wide outages in single-process deployments.
Root Cause
The root cause is missing input validation on the bytecount value parsed from the %%BeginBinary: directive. Pillow trusted the attacker-controlled integer and passed it directly to seek(), which accepts negative offsets when used with os.SEEK_CUR. Combined with the absence of a forward-progress check in the parsing loop, this permits an infinite reparse cycle [CWE-835].
Attack Vector
An attacker delivers a malicious EPS file to any endpoint that opens it with Pillow. Delivery channels include file upload forms, email attachment scanners, document conversion APIs, and CMS media processing. No authentication or user interaction is required beyond the target opening the file.
trailer_reached = True
elif bytes_mv[:14] == b"%%BeginBinary:":
bytecount = int(byte_arr[14:bytes_read])
+ if bytecount < 0:
+ msg = "BeginBinary bytecount cannot be negative"
+ raise ValueError(msg)
self.fp.seek(bytecount, os.SEEK_CUR)
bytes_read = 0
Source: Pillow commit 03992618 — the patch raises ValueError when a negative bytecount is encountered, terminating the parse instead of seeking backwards.
Detection Methods for CVE-2026-59203
Indicators of Compromise
- EPS files containing a %%BeginBinary: directive followed by a negative integer value.
- Python worker processes stuck at 100% CPU while holding an open file descriptor to a .eps or EPS-typed upload.
- Repeated identical seek operations on the same file offset observed in strace or process tracing output.
Detection Strategies
- Statically scan uploaded EPS files for the byte pattern %%BeginBinary: followed by a - sign before parsing them with Pillow.
- Enforce per-request CPU and wall-clock timeouts on image parsing workers to surface runaway processes.
- Inventory Python environments for Pillow versions in the 12.0.0 through 12.2.0 range using pip list or SBOM tooling.
Monitoring Recommendations
- Alert on sustained high CPU utilization by processes invoking PIL.EpsImagePlugin.
- Track error rates and processing latency for image upload endpoints and flag deviations tied to EPS content types.
- Log filename, MIME type, and file size for every EPS file processed to support forensic review.
How to Mitigate CVE-2026-59203
Immediate Actions Required
- Upgrade Pillow to version 12.3.0 or later across all Python environments, including containers and serverless runtimes.
- Reject EPS uploads at the application boundary until the upgrade is verified in production.
- Apply strict processing timeouts to any code path invoking Image.open() on user-supplied content.
Patch Information
The fix is available in Pillow 12.3.0. Details are published in the GitHub Security Advisory GHSA-pg7v-jwj7-p798 and merged via pull request #9708. The 12.3.0 release notes enumerate the fixed CVEs.
Workarounds
- Disable the EPS plugin by removing or not importing PIL.EpsImagePlugin and unregistering it from Image.OPEN if EPS support is not required.
- Pre-validate EPS files and reject any where the %%BeginBinary: directive is followed by a non-positive integer.
- Isolate image parsing in sandboxed workers with hard CPU and memory limits enforced by cgroups or container runtime constraints.
# Upgrade Pillow to the patched release
pip install --upgrade "Pillow>=12.3.0"
# Verify the installed version
python -c "import PIL; print(PIL.__version__)"
# Optional: disable EPS support at runtime if not needed
python -c "from PIL import Image, EpsImagePlugin; Image.unregister_open(EpsImagePlugin.EpsImageFile.format)"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

