Jul 21, 2026·5 min read·39 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.
Grav CMS prior to version 1.7.53 and 2.0.0-rc.8 is vulnerable to an unauthenticated remote denial of service (DoS) vulnerability. By supplying crafted query parameters with extremely large dimensions to image assets, remote unauthenticated attackers can force the server to allocate massive amounts of system memory, leading to kernel Out-Of-Memory (OOM) termination of web worker processes.
CVE-2026-53657 is a local privilege escalation vulnerability in Lima (lima-vm/lima) affecting versions prior to 2.1.3 when configured with the QEMU driver. The guest agent daemon, running as root, creates its communication socket `/run/lima-guestagent.sock` with world-writable permissions (0777). This allows unprivileged local users to command the agent to establish arbitrary tunnels, including to privileged local UNIX sockets (like D-Bus). Because the target daemon authenticates the incoming connection using the credentials of the root-owned guest agent (via SO_PEERCRED), unprivileged users can perform root operations, resulting in complete guest VM compromise.
An unauthenticated Denial of Service vulnerability exists in the s2n-quic library's CryptoStream reassembler due to a lack of buffer limits on out-of-order cryptographic frames. An attacker can transmit a crafted CRYPTO frame with an extremely high offset and nominal payload, forcing the receiver to execute unbounded memory allocations and causing service crashes.
A JNDI Injection and Deserialization Gadget vulnerability exists in mchange-commons-java prior to version 0.6.0. The com.mchange.v2.naming.JavaBeanObjectFactory component permits arbitrary class instantiation and setter invocation, allowing attackers to perform Server-Side Request Forgery (SSRF) and remote class loading.
SurrealDB versions supporting element-level SELECT permissions on arrays are vulnerable to a logical authorization bypass. Due to an index-shifting error during array filtration, restricted elements can skip permission checks and leak to unauthorized record users.
CVE-2026-12243 is a path traversal vulnerability in the Natural Language Toolkit (NLTK) version 3.9.4. The flaw exists because the input validation routine fails to account for percent-encoded directory traversal sequences like '..%2f' before passing them to urllib.request.url2pathname(), which decodes them into active traversal sequences.