CVE-2026-59204 Overview
CVE-2026-59204 is a memory exhaustion vulnerability in Pillow, the widely deployed Python imaging library. The flaw resides in src/libImaging/Jpeg2KDecode.c, where the decoder accumulates total_component_width across every tile in a JPEG2000 image rather than recomputing the value per tile. A crafted tiled JPEG2000 file can force substantially higher transient memory allocation during decoding, triggering out-of-memory failures in the host process. The issue affects Pillow versions 8.2.0 through 12.2.0 and is fixed in version 12.3.0. Because Pillow is embedded in web applications, image processing pipelines, and machine learning workflows, remote attackers can trigger denial-of-service conditions by supplying malicious image inputs.
Critical Impact
Remote attackers can send a crafted tiled JPEG2000 file to any service using Pillow to decode untrusted images, causing memory exhaustion and process termination without authentication or user interaction.
Affected Products
- Python Pillow versions 8.2.0 through 12.2.0
- Applications embedding vulnerable Pillow releases for JPEG2000 (.jp2, .j2k) decoding
- Web services, image processing pipelines, and ML systems accepting user-supplied images
Discovery Timeline
- 2026-07-14 - CVE-2026-59204 published to NVD
- 2026-07-14 - Last updated in NVD database
Technical Details for CVE-2026-59204
Vulnerability Analysis
The vulnerability is classified under [CWE-789] Memory Allocation with Excessive Size Value and [CWE-770] Allocation of Resources Without Limits or Throttling. Pillow's JPEG2000 decoder processes images composed of multiple tiles, each with its own component dimensions. The total_component_width variable was declared and initialized once before the tile-processing loop, then reused across iterations. Each tile added its component widths to the running total instead of recalculating a value scoped to the current tile.
An attacker who controls tile counts and component widths can inflate this cumulative value linearly with the number of tiles. The decoder subsequently uses the inflated total to size buffer allocations, leading to allocations far larger than the actual image geometry requires. Once memory pressure exceeds available resources, the host process crashes or the operating system terminates it via the out-of-memory killer.
Root Cause
The root cause is variable scope misuse in Jpeg2KDecode.c. total_component_width was declared at function scope but treated as if it were per-tile, causing accumulation across the tile loop. The patch removes the outer declaration so the value is derived independently for each tile.
Attack Vector
Exploitation requires only that an attacker deliver a crafted JPEG2000 file to a vulnerable Pillow consumer. No authentication or user interaction is required. Any endpoint that calls Image.open() followed by decoding on attacker-controlled JPEG2000 bytes is exposed, including avatar upload handlers, thumbnail generators, and document processing services.
size_t tile_bytes = 0;
unsigned n, tile_height, tile_width;
int subsampling;
- int total_component_width = 0;
stream = opj_stream_create(BUFFER_SIZE, OPJ_TRUE);
Source: Pillow commit 13ada41. The patch removes the function-level declaration of total_component_width, forcing per-tile calculation and preventing cumulative growth across tiles.
Detection Methods for CVE-2026-59204
Indicators of Compromise
- Sudden memory spikes or OOM-killer events in processes that decode JPEG2000 images through Pillow
- Repeated crashes of image-processing workers immediately following upload of .jp2 or .j2k files
- Application logs showing MemoryError or PIL.Image.DecompressionBombError exceptions during JPEG2000 handling
Detection Strategies
- Inventory Python environments for Pillow versions between 8.2.0 and 12.2.0 using pip list or software composition analysis tools
- Instrument image ingestion endpoints to log file format, tile count, and decode-time memory delta for anomaly review
- Alert on JPEG2000 uploads with unusually high tile counts or component widths inconsistent with declared image dimensions
Monitoring Recommendations
- Track resident set size (RSS) growth of image-processing workers and correlate with request identifiers to isolate malicious inputs
- Monitor container and pod OOM-kill events in orchestration platforms such as Kubernetes
- Forward Pillow exception traces to centralized logging for rapid triage of decode failures
How to Mitigate CVE-2026-59204
Immediate Actions Required
- Upgrade Pillow to version 12.3.0 or later across all Python environments handling untrusted images
- Audit third-party packages that pin older Pillow versions and rebuild dependent container images
- Restrict accepted image formats at the application layer if JPEG2000 support is not required
Patch Information
The fix is included in Pillow 12.3.0. See the GitHub Security Advisory GHSA-vjc4-5qp5-m44j, the merged pull request #9704, and the 12.3.0 release notes for full details.
Workarounds
- Reject JPEG2000 uploads at the web application firewall or application layer until patching is complete
- Enforce per-process memory limits using cgroups, ulimit, or container resource caps to contain decode-time exhaustion
- Run image decoding in isolated worker processes with automatic restart to prevent service-wide outages
# Upgrade Pillow to the patched release
pip install --upgrade 'Pillow>=12.3.0'
# Verify installed version
python -c "import PIL; print(PIL.__version__)"
# Optional: constrain decoder memory via systemd for image workers
# /etc/systemd/system/image-worker.service.d/override.conf
# [Service]
# MemoryMax=512M
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

