Jul 21, 2026·5 min read·9 visits
A heap-based buffer overflow exists in Pillow prior to 12.3.0's ImageCms module. Lacking verification of image modes allows writing multi-byte output data into under-allocated buffers, potentially enabling remote code execution.
CVE-2026-59205 is a high-severity heap-based out-of-bounds write vulnerability affecting Pillow prior to version 12.3.0. The flaw stems from a validation omission in the ImageCmsTransform class where source and destination image modes are not checked against the configurations defined during the creation of the transform. An attacker can exploit this discrepancy to trigger a heap buffer overflow or an out-of-bounds read by supplying an under-allocated target image buffer.
Pillow incorporates the LittleCMS (lcms2) library via its ImageCms module to perform high-fidelity color profile conversions. The ImageCmsTransform class handles these transformations by establishing custom input and output pixel modes, which correspond to specific internal memory layouts.
The vulnerability, designated as CVE-2026-59205, manifests when an application processes transformations via apply() or apply_in_place(). These APIs fail to validate that the pixel modes of user-supplied images correspond to the formats expected by the compiled transformation object.
Because the native C extension _imagingcms only performs coordinate-based boundary checks, it readily processes images with mismatched formats. This discrepancy allows multi-byte pixel structures to be written into buffers allocated for single-byte pixel layouts.
The root cause of this vulnerability lies in the lack of type and mode validation within the src/PIL/ImageCms.py Python layer and the corresponding _imagingcms.c native component. During transformation compilation, a handle is initialized with predefined source and destination formats, which dictate how many bytes are read and written per pixel.
When cmsDoTransform() is executed, the destination image's row buffer pointers are supplied directly to the LittleCMS engine. If the compiled transformation outputs 4-byte pixels (such as RGBA) but the target image is allocated with a 1-byte pixel mode (such as L), LittleCMS continues to write 4 bytes per pixel into the destination buffer.
This behavior causes a controlled out-of-bounds write of 3 bytes per pixel into adjacent heap chunks. Conversely, if the input image mode contains fewer bytes than expected by the transformation engine, an out-of-bounds heap read occurs, exposing adjacent memory contents.
The vulnerability was mitigated in Pillow version 12.3.0 by incorporating check assertions directly into the high-level Python wrappers inside src/PIL/ImageCms.py.
Prior to the patch, the apply method did not perform any validation of input or output modes:
def apply(self, im, imOut=None):
if imOut is None:
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 imOutThe corrected implementation establishes strict equality validations prior to invoking the C extension:
def apply(self, im: Image.Image, imOut: Image.Image | None = None) -> Image.Image:
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 imOutThese checks ensure that the physical structures allocated for the images match the spatial logic expected by the native code.
Although the current validation checks successfully address the public API vector, implementing defenses purely at the Python layer introduces a potential gap in defensive controls. If an attacker is capable of executing limited python code, they can directly import and call the binary extension module _imagingcms.
Because the underlying C-code wrappers do not check the mode attribute of the ImagingCore structures, direct calls to the underlying transform engine still result in a heap out-of-bounds write. Furthermore, if custom image classes can spoof the .mode property while returning an under-allocated buffer on .getim(), the Python-level checks can be circumvented.
To ensure complete isolation, future iterations of Pillow should incorporate these size-assertion validations inside the native C extension _imagingcms.c before passing pointers to the lcms2 library.
To exploit this vulnerability, an attacker must submit an image that forces the application to perform a color space transformation where the source or target image buffers are mismatched. An application that automatically converts user uploads to a standardized color profile is highly vulnerable to this scenario.
Because the bytes written to the adjacent heap space represent the translated pixels of the source image, an attacker can construct custom pixel matrices to control the corrupted data. By crafting the input pixel coordinates and color values, the attacker can precisely overwrite adjacent metadata blocks, targeting function pointers or control structures on the heap to execute arbitrary code.
The vulnerability is assigned CVSSv3.1 score 7.5 (High) due to the potential for total loss of process availability. In environments where Pillow processes image uploads, exploitation immediately leads to process termination or denial of service.
In scenarios where memory protections such as ASLR are bypassed or where control over heap layouts is mature, heap corruption can be weaponized to compromise system integrity. This vulnerability is of critical concern for multi-tenant image hosting services and document processing pipelines.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Pillow python-pillow | < 12.3.0 | 12.3.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-787 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 | 7.5 (High) |
| Impact | Availability (High) |
| Exploit Status | Proof of Concept available in tests |
| KEV Status | Not listed |
The software writes data past the end, or before the beginning, of the intended buffer, resulting in corruption of data, a crash, or code execution.
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.
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.
A Denial of Service vulnerability exists in the JPEG2000 decoder of Pillow (versions 8.2.0 to 12.2.0) due to memory allocation state accumulation across tiles, leading to rapid process termination.