Skip to main content
Vulnerability Database/CVE-2026-112394

CVE-2026-112394: Pillow Buffer Overflow Vulnerability

CVE-2026-112394 is a buffer overflow vulnerability in Pillow Python imaging library that allows reading past input buffer boundaries, potentially disclosing heap memory or causing crashes. This article covers technical details, affected versions, impact assessment, and mitigation strategies.

Published:

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.

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

c
// 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.
bash
# 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.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.