CVE-2026-59199
Summary
Pillow's public image coordinate APIs can trigger a native heap out-of-bounds
write when given coordinates near the signed 32-bit integer limits. In 4-byte
pixel modes such as RGBA, this becomes a controlled backward heap underwrite:
for a source image of width W, Pillow writes 4 * W attacker-controlled bytes
starting 4 * W bytes before the destination row pointer. With successful large
image allocation, the theoretical upper bound is ~2 GiB backwards from
the destination row.
Minimal public API trigger:
from PIL import Image
INT_MIN = -(1 << 31)
src = Image.new("RGBA", (2, 1), (0x41, 0x42, 0x43, 0x44))
dst = Image.new("RGBA", (8, 1))
dst.paste(src, ((1 << 31) - 2, 0, INT_MIN, 1))
The same root cause is also reachable through Image.crop() and
Image.alpha_composite(). No private API, ctypes, custom Python object, or
malformed image file is needed.
This has been confirmed as an ASAN heap-buffer-overflow write. On normal
non-ASAN Pillow builds, the minimal trigger corrupts the heap and aborts with
double free or corruption (out)
Details
src/PIL/Image.py:paste() accepts a 4-tuple box and passes it to the native
ImagingCore.paste() method:
self.im.paste(source, box)
src/_imaging.c:_paste() parses the four Python coordinates into signed int
values and calls ImagingPaste():
int x0, y0, x1, y1;
PyArg_ParseTuple(args, "O(iiii)|O!", &source, &x0, &y0, &x1, &y1, ...);
status = ImagingPaste(self->image, PyImaging_AsImaging(source), ..., x0, y0, x1, y1);
src/libImaging/Paste.c:ImagingPaste() computes and clips the region using
signed int arithmetic:
xsize = dx1 - dx0;
ysize = dy1 - dy0;
if (dx0 + xsize > imOut->xsize) {
xsize = imOut->xsize - dx0;
}
With dx0 = 2147483646 and dx1 = -2147483648, dx1 - dx0 wraps to 2.
That matches the 2-pixel source image, so the size check passes. The later
dx0 + xsize clip check wraps around and does not reject the out-of-bounds
destination.
For 4-byte pixel modes such as RGBA, the paste loop then multiplies dx by
pixelsi
⚡ Watch CVE-2026-59199
Get an email if CVE-2026-59199 is added to CISA KEV, gains public exploit code, or a new advisory cites it — max one per day, one-click unsubscribe.
Exploitation outlook
- Low exploitation risk0.39% 30-day exploitation probability — currently an unlikely target, but scores change as exploit code circulates. Riskier than 31% of all EPSS-scored CVEs.
Advisory coverage (2)
External references
Embed the live status
— this badge updates automatically when the KEV or exploit status changes. How to embed it →
[](https://www.csirts.com/cve/CVE-2026-59199)