CVE-2026-112394 Overview
CVE-2026-112394 is an out-of-bounds read vulnerability in Pillow, the Python imaging library widely used for image processing in web applications, machine learning pipelines, and data processing workflows. Versions prior to 13.0.0 contain a flaw in the P;2L and P;4L raw decoders that allows reading past the end of an input buffer. The issue stems from a mismatch between how ImagingRawDecode calculates row sizes and how the unpackers process separately padded bit planes. An attacker supplying a crafted image can disclose up to three adjacent heap bytes in output pixels or crash the process. The vulnerability is tracked as [CWE-126] Buffer Over-read and is fixed in Pillow 13.0.0.
Critical Impact
Processing a maliciously crafted image through Pillow's P;2L or P;4L raw decoders can leak up to three adjacent heap bytes into decoded output pixels or trigger a process crash, enabling information disclosure or denial of service.
Affected Products
- Pillow (Python Imaging Library) versions prior to 13.0.0
- Python applications using Pillow's raw decoder with P;2L or P;4L rawmodes
- Downstream services that accept user-supplied images processed by vulnerable Pillow versions
Discovery Timeline
- 2026-10-19 - CVE-2026-112394 published to the National Vulnerability Database (NVD)
- 2026-10-22 - Last updated in NVD database
Technical Details for CVE-2026-112394
Vulnerability Analysis
The vulnerability resides in Pillow's raw image decoder handling of two palette rawmodes: P;2L (2-bit planar) and P;4L (4-bit planar). In ImagingRawDecode, the decoder computes an accepted buffer size using a packed-pixel row calculation. However, the actual unpackers for these modes process the data as separately padded bit planes, each with its own row padding.
The mismatch allows a caller to supply input dimensions and a buffer where the accepted packed-pixel footprint is smaller than the unpackers' real bit-plane footprint. During decoding, the unpackers walk past the end of the supplied buffer and read into adjacent heap memory. Up to three bytes of adjacent heap content can be copied into the output pixel data, resulting in information disclosure. In less favorable memory layouts, the read triggers a crash and denial of service.
Root Cause
The root cause is an inconsistency between row-size accounting in ImagingRawDecode and the per-plane layout used by the P;2L and P;4L unpackers. The decoder validates input length against a packed-pixel row size, while the unpackers require space for independently padded bit planes. The validation therefore accepts buffers that are smaller than the unpackers actually consume.
Attack Vector
An attacker needs to cause the victim application to decode a crafted image using one of the affected rawmodes. This is a plausible path in any service that accepts untrusted image input, including upload handlers, thumbnailing services, OCR pipelines, and machine-learning preprocessing. Successful exploitation leaks heap bytes into the decoded image, which the attacker can retrieve if the application returns the decoded output.
# Patch excerpt from src/PIL/Image.py - removes an incomplete length check
# in favor of a correct bit-plane row size calculation downstream.
# may pass tuple instead of argument list
decoder_args = decoder_args[0]
- if decoder_args and decoder_args[0] in {"P;2L", "P;4L"}:
- multiple = 4 if decoder_args[0] == "P;2L" else 8
- if len(data) % multiple:
- msg = "not enough image data"
- raise ValueError(msg)
-
# default format
if decoder_name == "raw" and decoder_args == ():
decoder_args = self.mode
Source: GitHub Pillow Commit 392ee6f
// Patch excerpt from src/_imaging.c - rejects planar palette rawmodes where
// they are not meaningful, preventing the mismatched decode path.
return NULL;
}
+ // Planar palette rawmodes are not meaningful for palette data.
+ if (rawmode == IMAGING_RAWMODE_P_2L || rawmode == IMAGING_RAWMODE_P_4L) {
+ PyErr_SetString(PyExc_ValueError, wrong_raw_mode);
+ return NULL;
+ }
+
unpack = ImagingFindUnpacker(palette_mode, rawmode, &bits);
if (!unpack) {
PyErr_SetString(PyExc_ValueError, wrong_raw_mode);
Source: GitHub Pillow Commit 392ee6f
Detection Methods for CVE-2026-112394
Indicators of Compromise
- Python processes raising ValueError with messages such as not enough image data or wrong_raw_mode when handling user-supplied images.
- Unexpected process crashes or segmentation faults in services that invoke Pillow's raw decoder on uploaded images.
- Image upload traffic specifying unusual palette modes (P;2L, P;4L) in applications that normally handle standard formats such as PNG or JPEG.
Detection Strategies
- Inventory Python environments and container images for Pillow versions below 13.0.0 using software composition analysis.
- Instrument image-handling endpoints to log decoder arguments and detect calls that reference P;2L or P;4L rawmodes.
- Enable AddressSanitizer or similar heap-boundary instrumentation in test environments to surface out-of-bounds reads during fuzzing of image inputs.
Monitoring Recommendations
- Monitor application logs for repeated Pillow exceptions correlated with specific client IPs or upload sessions.
- Alert on crash loops in image-processing workers and preserve core dumps for analysis.
- Track outbound responses that return decoded image data to users, as these are the paths through which leaked heap bytes would exfiltrate.
How to Mitigate CVE-2026-112394
Immediate Actions Required
- Upgrade Pillow to version 13.0.0 or later in all production, staging, and build environments.
- Audit application code for direct use of the raw decoder with P;2L or P;4L rawmodes and remove or restrict such code paths.
- Validate and constrain image formats accepted from untrusted sources, rejecting unusual palette modes before they reach Pillow.
Patch Information
The fix is included in Pillow 13.0.0. The patch rejects planar palette rawmodes (P;2L, P;4L) in the C extension where they are not meaningful and corrects row-size handling in the decoder. See the GitHub Security Advisory GHSA-4558-3h8r-v8xp and the Pillow 13.0.0 release notes for details.
Workarounds
- If upgrading immediately is not feasible, wrap image decoding in strict format allowlists and reject inputs that request P;2L or P;4L rawmodes.
- Isolate image-processing workloads in sandboxed workers with minimal privileges to limit the impact of a crash or information disclosure.
- Disable or remove features that expose Pillow's raw decoder arguments to end users.
# Upgrade Pillow to the fixed version
pip install --upgrade "Pillow>=13.0.0"
# Verify the installed version
python -c "import PIL; print(PIL.__version__)"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

