Jul 21, 2026·6 min read·6 visits
Unvalidated negative byte counts in Pillow's EPS image parser trigger an infinite backward stream-seek loop, resulting in 100% CPU utilization and application hang without requiring image rendering or a Ghostscript installation.
A denial-of-service (DoS) vulnerability in Pillow (Python Imaging Library) versions 12.0.0 through 12.2.0 allows unauthenticated remote attackers to trigger 100% CPU utilization and hang the processing thread. The issue occurs within the Encapsulated PostScript (EPS) image parser (PIL/EpsImagePlugin.py) due to missing validation on the byte count parsed from %%BeginBinary: comments, allowing negative values to cause an infinite backward stream seek loop. This formatting-level state-looping issue occurs during the initial format sniffing phase inside Image.open() and does not require the system Ghostscript interpreter to be executed or present. It is resolved in version 12.3.0.
Pillow incorporates a dedicated module to parse Encapsulated PostScript (EPS) files. This parser, located in PIL/EpsImagePlugin.py, processes PostScript files to read metadata and extract preview images. When an application attempts to process an incoming image via Image.open(), Pillow runs auto-detection routines to match the file against known image headers, meaning the EPS parser is triggered automatically upon encountering EPS-specific magic bytes.
Due to a lack of input validation in the parser's logic for processing Document Structuring Conventions (DSC) comments, the parser can be forced into an infinite loop state. This vulnerability class maps directly to CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop').
An unauthenticated remote attacker can exploit this vulnerability to consume 100% CPU resource allocations on the application server. Because the flaw is executed during the format sniffing stage, it is processed before rendering, meaning the attack requires minimal compute cost for the attacker and is highly effective at exhausting single-threaded application workers.
The root cause of CVE-2026-59203 resides within the parsing of the %%BeginBinary: <bytecount> DSC comment directive inside PIL/EpsImagePlugin.py. According to the Adobe PostScript Document Structuring Conventions, the %%BeginBinary: directive specifies that a designated number of bytes of raw binary data follows immediately. The parser reads the integer string following this header to determine how many bytes to skip forward to bypass the binary segment.
The vulnerable implementation uses the statement self.fp.seek(bytecount, os.SEEK_CUR) to perform a relative forward seek from the current file pointer position. However, the parser does not enforce validation checks to guarantee that the converted bytecount integer is a non-negative value.
When a negative integer is supplied as the byte count (such as %%BeginBinary:-21), the seek operation is executed with a negative value, triggering a backward relative seek. The file pointer is repositioned to a point prior to the %%BeginBinary: directive line. During the subsequent iteration of the line-reading loop, the parser processes the exact same line again, creating an infinite loop that isolates execution within the thread, leading to total thread lockup and CPU exhaustion.
To understand the technical structure of the vulnerability, examine the parsing loop in the vulnerable version of PIL/EpsImagePlugin.py. The parser reads blocks of data from the file stream and checks the leading characters of the slice against known DSC comment headers:
# Vulnerable implementation prior to Pillow 12.3.0
elif bytes_mv[:14] == b"%%BeginBinary:":
bytecount = int(byte_arr[14:bytes_read])
self.fp.seek(bytecount, os.SEEK_CUR)In this sequence, bytecount is derived directly from user-controlled input without bounds or sign checking. The file object pointer (self.fp) is shifted backward relative to its current position when bytecount is negative.
The patch implemented in Pillow 12.3.0 resolves this logical loophole by checking if the evaluated integer is less than zero. If the constraint check fails, a ValueError is raised, immediately terminating the file parsing sequence and avoiding the seek operation:
# Patched implementation in Pillow 12.3.0
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)This validation mechanism is highly robust because it halts execution before any offset modifications occur on the file stream, preventing infinite iteration. The fix is considered complete as there are no other relative seek calls on raw user-controlled integers in this parsing scope.
Exploitation of CVE-2026-59203 is trivial and requires zero special privileges or system configurations. An attacker merely needs to submit a file containing a valid EPS header and a negative %%BeginBinary value to an endpoint that processes user uploads through Pillow. Because format verification is content-based, renaming the malicious EPS payload to .png or .jpg does not neutralize the vector; Pillow still routes the input stream to the vulnerable EPS parser.
The minimal payload structure contains standard PostScript headers to satisfy initial format detection, immediately followed by the malformed directive:
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 100 100
%%BeginBinary:-21Below is a conceptual Mermaid flow diagram showing how the file stream pointer is trapped inside the backward-seeking loop:
When the application processes this payload, the thread hosting the processing task enters a tight loop, driving its CPU usage to 100%. In single-threaded synchronous architectures, this denies service to all concurrent users instantly.
The impact of this vulnerability is characterized primarily by application-level denial of service. The CVSS v3.1 base score is calculated at 5.3 (Medium), with a low impact on availability. This CVSS classification assumes a localized process impact; however, in standard production architectures handling synchronous image resizing, multiple uploads of this payload can easily lock up all available workers, culminating in an application-wide outage.
Because the vulnerability is triggered during the format sniffing step, the code path is executed inside Image.open(). This eliminates the prerequisite for the actual image to be loaded or rendered via Image.load(). Furthermore, it completely bypasses the requirement for the host environment to have Ghostscript installed, making the attack highly reliable across standard Python containerized environments.
As of mid-2026, there are no documented instances of active exploitation in the wild, placing the Exploit Maturity at the Proof-of-Concept (PoC) stage. Due to the minimal complexity required to produce a functional exploit payload, detection and prevention at the perimeter are highly recommended.
The primary remediation path is upgrading the Python environment to utilize Pillow version 12.3.0 or later, which correctly sanitizes the %%BeginBinary directive integer. If an immediate upgrade is unfeasible, developers should restrict the list of allowed image types passed to Pillow during image loading. Bypassing automatic format sniffing stops the EPS parser from executing:
# Safe file-handling configuration
img = Image.open(user_file, formats=["PNG", "JPEG", "WEBP"])Additionally, network and application administrators can configure Web Application Firewalls (WAF) or intrusion detection signatures to block or flag incoming files matching the malformed EPS byte footprint. A custom ModSecurity WAF rule can be drafted to detect files containing the malicious sequence:
SecRule REQUEST_BODY "(?i)%%BeginBinary:\\s*-\\d+" "id:1000001,phase:2,deny,status:400,msg:'Blocked suspected CVE-2026-59203 exploit attempt'"For local file systems or upload processing pipelines, security teams can employ the YARA rule supplied in this report to continuously monitor for the presence of malformed vector files containing negative bytecounts.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
Pillow python-pillow | >= 12.0.0, < 12.3.0 | 12.3.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-835: Loop with Unreachable Exit Condition ('Infinite Loop') |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 5.3 (Medium) |
| EPSS Score | 0.0039 (Percentile: 31.40%) |
| Impact | Denial of Service (Thread Hang / CPU Exhaustion) |
| Exploit Status | Proof-of-Concept (PoC) available |
| CISA KEV Status | Not Listed |
The program contains an iteration loop with an exit condition that cannot be met, causing it to loop forever.
An improper encoding and escaping vulnerability in the .NET SMTP client component allows network-based attackers to perform SMTP command smuggling and email spoofing by injecting control characters into email fields.
CVE-2026-50651 is a high-severity Denial of Service vulnerability in Microsoft .NET runtimes, SDKs, and Visual Studio installations. It stems from a weakness in System.Net.Http (CWE-770), where the HTTP/2 connection handling state machine fails to throttle server-initiated protocol streams and control frames. An attacker-controlled server can exploit this by returning highly fragmented or infinite control and continuation frame sequences. This forces the client to allocate memory indefinitely on the managed heap, eventually provoking an unhandled Out-of-Memory (OOM) exception and application crash.
A heap out-of-bounds write vulnerability exists in Pillow prior to version 12.3.0 due to an integer overflow during image expansion calculations. The subsequent patch introduced a division-by-zero regression causing denial of service.
CVE-2026-59198 is a high-severity heap out-of-bounds read vulnerability in Pillow, the Python imaging library, affecting versions from 5.2.0 up to 12.3.0. The vulnerability occurs in the TGA RLE compression path due to a calculation mismatch between the allocated packed 1-bit row buffer and the byte-level pixel stride assumption in the C-level encoder. This mismatch allows an attacker to leak up to approximately 57 KB of adjacent process heap memory directly into generated TGA image files.
A critical signed 32-bit integer overflow vulnerability was identified in Pillow (Python Imaging Library) versions prior to 12.3.0. The vulnerability resides within the native C extension library (libImaging) during coordinate and bounding box calculations in functions like ImagingPaste and ImagingFill2. Exploitation can bypass bounds and clipping safety checks, leading to a controlled heap backward underwrite and application crash.
CVE-2026-59200 is a high-severity uncontrolled resource consumption vulnerability in the Pillow Python Imaging Library. The flaw resides in the PDF stream decoder, allowing remote, unauthenticated attackers to trigger host out-of-memory crashes by submitting malicious PDF decompression bombs.