Three CVSS 9.2 vulnerabilities in the Python imaging library, allow remote code execution and heap corruption via a single malicious image upload
Overview
Three critical Pillow vulnerabilities (CVSS 9.2, disclosed 2026-10-19) let a crafted EPS, TIFF or JPEG file trigger command execution or heap corruption in any Python service that processes user-supplied images. All are fixed in Pillow 13.0.0. The excerpts below are from the vulnerable source.
Pillow is one of the most popular Python packages, and the most popular image processing library, with an estimated 436M monthly downloads.
What is Pillow?
Pillow is an image-processing library for Python – a maintained fork of the original PIL (Python Imaging Library). It opens, converts, resizes, thumbnails and saves images across dozens of formats (JPEG, PNG, TIFF, GIF, WebP, EPS and more), and is a near-ubiquitous dependency: web frameworks (Django/Flask image handling), thumbnail and avatar pipelines, document and PDF tooling, and most Python machine-learning and computer-vision stacks pull it in directly or transitively.
Because it routinely parses untrusted, user-supplied image bytes, a memory-safety or injection bug in Pillow is reachable from a plain file upload across a huge range of services.
Compromised Packages
| Package | CVE | Component | Versions | Fixed Versions | Ecosystem | CVSS v4.0 |
| pillow | CVE-2026-112900 | EPS via Ghostscript (`EpsImagePlugin`) | >= 2.6.0, < 13.0.0 | 13.0.0 | PyPI | 9.2 Critical |
| pillow | CVE-2026-112393 | TIFF write (`_tiffWriteProc`) | >= 2.0.0, < 13.0.0 | 13.0.0 | PyPI | 9.2 Critical |
| pillow | CVE-2026-112403 | JPEG decode (`ImagingJpegDecode`) | < 13.0.0 | 13.0.0 | PyPI | 9.2 Critical |
CVE-2026-112900 – EPS argument injection -> RCE
Pillow renders EPS images by shelling out to Ghostscript. `EpsImagePlugin.Ghostscript` passes the caller-controlled input filename after `-f` without converting it to an absolute path, so a filename that starts with `-` is parsed by Ghostscript as an option. Combined with Ghostscript’s `@argfile` syntax (a leading `@` names a file whose contents become extra arguments) and control of that file, an attacker who controls the filename Pillow opens can inject Ghostscript options and run arbitrary commands – even under the default `-dSAFER`.

CVE-2026-112393 – TIFF write heap overflow (BytesIO)
When a compressed TIFF is saved to a file-like object with no real OS file descriptor (e.g. `io.BytesIO`), Pillow routes libtiff’s output through its `_tiffWriteProc` callback. The grow loop sizes the reallocation from `state->size` (the prior buffer size) instead of `state->loc` (the current write position), so for output larger than 64 KiB libtiff can seek past the buffer and `_TIFFmemcpy` writes at `state->loc` beyond the allocation – a heap overflow, plus disclosure of stale heap bytes in the unwritten alignment gaps. Saving to a real file path (which has a `fileno()`) is not affected.

CVE-2026-112403 – JPEG draft/thumbnail heap overflow
Pillow’s JPEG decoder writes a full-width scanline into `state->buffer`, which is sized from the tile / draft extents (the unpacker), not from the JPEG header. An attacker who feeds a crafted 8-bit lossless (SOF3) JPEG to an application that requests downscaling via `draft()` or `thumbnail()` makes libjpeg produce lines wider than the buffer, overflowing the heap – crash, and potentially code execution. Newer libjpeg-turbo builds accept the malformed input that older libjpeg-turbo 2.x / IJG builds reject.

Recommendations
- Upgrade now. `pip install -U “Pillow>=13.0.0″` and rebuild any wheels, containers or base images that vendor it. This is the only complete fix for all three CVEs.
- Reduce the image attack surface. Accept only the formats you actually need; never pass an attacker-controlled filename to `Image.open()` for EPS, and keep the Ghostscript (`gs`) binary off hosts that process untrusted uploads (CVE-2026-112900 is only reachable when `gs` is present). Treat `draft()` / `thumbnail()` on untrusted JPEGs and TIFF saves to in-memory buffers as the sensitive paths.