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

CVE-2026-59205: Python Pillow Buffer Overflow Vulnerability

CVE-2026-59205 is a buffer overflow vulnerability in Python Pillow that causes heap corruption through ImageCmsTransform.apply() API misuse. This article covers technical details, affected versions, and mitigation strategies.

Published:

CVE-2026-59205 Overview

CVE-2026-59205 is a heap corruption vulnerability in Pillow, the widely used Python imaging library. The flaw exists in the ImageCms.ImageCmsTransform.apply(im, imOut) API. When a caller supplies an output image whose mode does not match the transform's declared output mode, the library triggers controlled native heap corruption [CWE-787]. The issue affects all Pillow versions prior to 12.3.0 and is fixed in that release. Applications that process untrusted images or accept caller-controlled color mode parameters are exposed to denial-of-service and potential memory-corruption impacts.

Critical Impact

An attacker able to influence the imOut image mode passed to ImageCmsTransform.apply() can corrupt the native heap, leading to process crashes and potential exploitation of the underlying C-level image buffers.

Affected Products

  • Python Pillow versions prior to 12.3.0
  • Applications embedding Pillow's ImageCms color management module
  • Downstream Python packages that expose ImageCmsTransform.apply() to user-supplied image data

Discovery Timeline

  • 2026-07-14 - CVE-2026-59205 published to NVD
  • 2026-07-14 - Last updated in NVD database

Technical Details for CVE-2026-59205

Vulnerability Analysis

The vulnerability resides in Pillow's ImageCms module, which wraps the Little CMS (LCMS) color management library through a native extension. The ImageCmsTransform.apply(im, imOut) method performs an ICC color profile transform from an input image im into an output image imOut. The transform stores an input_mode and output_mode that describe the pixel format (for example RGB, RGBA, CMYK, or L) the underlying LCMS operation expects.

Prior to version 12.3.0, the apply() method did not validate that im.mode matched self.input_mode or that imOut.mode matched self.output_mode before invoking the native transform. The native code assumes a fixed bytes-per-pixel layout derived from the declared modes and writes into imOut.getim() based on that assumption. Supplying a caller-controlled imOut with a mismatched mode causes writes past the allocated pixel buffer, resulting in controlled heap corruption.

Root Cause

The root cause is missing input validation [CWE-787] at the Python-to-native boundary in src/PIL/ImageCms.py. The method delegated pixel-format assumptions to the LCMS transform without confirming that the Python Image objects matched those assumptions. Because the native transform derives buffer sizes from mode metadata, a mode mismatch produces an out-of-bounds write in the native heap.

Attack Vector

Exploitation requires an attacker to influence the arguments passed to ImageCmsTransform.apply(). This is realistic in image-processing pipelines, web services, or automated conversion tools that accept caller-supplied color modes or that build transforms from untrusted ICC profiles. Successful exploitation reliably crashes the Python process and may allow further memory-corruption primitives depending on allocator state.

python
# Source: https://github.com/python-pillow/Pillow/commit/a9ffc42bedf4fc0a7ef8d6486e7f9e81e3397721
# Security patch in src/PIL/ImageCms.py - validate modes before invoking native transform

    def apply(self, im: Image.Image, imOut: Image.Image | None = None) -> Image.Image:
-        if imOut is None:
+        if im.mode != self.input_mode:
+            msg = "mode mismatch"
+            raise ValueError(msg)
+        if imOut is not None:
+            if imOut.mode != self.output_mode:
+                msg = "mode mismatch"
+                raise ValueError(msg)
+        else:
             imOut = Image.new(self.output_mode, im.size, None)
         self.transform.apply(im.getim(), imOut.getim())
         imOut.info["icc_profile"] = self.output_profile.tobytes()
         return imOut

    def apply_in_place(self, im: Image.Image) -> Image.Image:
-        if im.mode != self.output_mode:
-            msg = "mode mismatch"
-            raise ValueError(msg)  # wrong output mode
-        self.transform.apply(im.getim(), im.getim())
-        im.info["icc_profile"] = self.output_profile.tobytes()
-        return im
+        return self.apply(im, im)

The patch adds explicit mode comparisons for both im and imOut before calling self.transform.apply(). It also consolidates apply_in_place() to reuse the validated apply() path, ensuring a single enforcement point.

Detection Methods for CVE-2026-59205

Indicators of Compromise

  • Unexpected Python process crashes with SIGSEGV or SIGABRT in workers that invoke PIL.ImageCms
  • Glibc heap diagnostic messages such as double free or corruption, malloc(): corrupted top size, or free(): invalid next size in application logs
  • Image processing worker restarts correlated with uploads containing unusual ICC profiles or color modes

Detection Strategies

  • Inventory Python environments and identify installations where pillow is older than 12.3.0 using pip show pillow or SBOM tooling
  • Perform static code review for direct calls to ImageCms.ImageCmsTransform.apply() and apply_in_place() where either argument is influenced by untrusted input
  • Enable Python fault handlers (faulthandler.enable()) in image processing services to capture native tracebacks that reveal ImageCms frames

Monitoring Recommendations

  • Monitor image-processing services for abnormal crash rates and correlate with recently uploaded files
  • Alert on Pillow versions below 12.3.0 reported by software composition analysis and container image scanning
  • Log ICC profile transformation operations and flag inputs whose mode does not match the configured transform pipeline

How to Mitigate CVE-2026-59205

Immediate Actions Required

  • Upgrade Pillow to version 12.3.0 or later across all Python environments, including base images, virtual environments, and serverless runtimes
  • Rebuild and redeploy container images and application bundles that vendor Pillow as a dependency
  • Audit application code paths that expose ImageCms functionality to untrusted image data and add explicit mode validation as a defense-in-depth control

Patch Information

The fix is available in Pillow 12.3.0. See the Pillow Release Version 12.3.0, the upstream commit a9ffc42, the pull request #9715, and the GitHub Security Advisory GHSA-9hw9-ch79-4vh6 for details.

Workarounds

  • Wrap calls to ImageCmsTransform.apply() with explicit checks that im.mode == transform.input_mode and, when supplied, imOut.mode == transform.output_mode
  • Do not accept caller-controlled imOut buffers from untrusted sources; let Pillow allocate the output image internally by passing imOut=None
  • Reject or normalize uploaded images to a fixed mode before invoking any ImageCms transform
bash
# Upgrade Pillow to the fixed version
python -m pip install --upgrade "Pillow>=12.3.0"

# Verify installed version
python -c "import PIL, sys; print(PIL.__version__); sys.exit(0 if tuple(map(int, PIL.__version__.split('.')[:2])) >= (12, 3) else 1)"

# For requirements pinning
# requirements.txt
# Pillow>=12.3.0

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

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.