Vulnerability DatabaseCVE-2026-112393

CVE-2026-112393: 
Python vulnerability analysis and mitigation

Overview

CVE-2026-112393 is a heap-based buffer overflow and stale-heap disclosure vulnerability in Pillow, the Python imaging library, affecting versions 2.0.0 through 12.x (fixed in 13.0.0). The flaw exists in the _tiffWriteProc callback in src/libImaging/TiffDecode.c, triggered when saving compressed TIFF data through libtiff to an in-memory target without a usable file descriptor (e.g., io.BytesIO). The bug was introduced in 2013 (commit e782fe7) and has been present since Pillow 2.0.0. It carries a CVSS v4.0 base score of 9.2 (Critical) (GitHub Advisory, Feedly).

Technical details

The root cause (CWE-122: Heap-based Buffer Overflow) is an incorrect buffer sizing calculation in _tiffWriteProc: the realloc() call sizes the new buffer from state->size + size instead of state->loc + size. When libtiff writes the TIFF directory, it seeks past the current end of data and writes out-of-line tag values there; because the allocation does not account for the current write position (loc), the first out-of-line tag value written after the seek can overflow the heap buffer by up to the IFD size (12 bytes per directory entry — 126 bytes minimum, up to 2,384 bytes with a 331-entry IFD). The overflow content is attacker-controlled tag data (e.g., ImageDescription, DocumentName, XMP packet, or ICC profile). A secondary, independent issue causes unwritten alignment gaps in compressed TIFF output larger than 64 KiB to leak stale heap bytes into the output file, requiring no crafted tag. Exploitation requires: (1) a vulnerable Pillow version, (2) the service saves to a non-file target such as BytesIO, and (3) an attacker-controlled out-of-line TIFF tag reaches libtiff — achievable via direct TIFF re-save or through a retained ICC profile that survives convert()/resize()/copy() (GitHub Advisory, Fix Commit).

Impact

Successful exploitation can crash the worker process via SIGABRT (denial of service) due to glibc detecting heap corruption (malloc(): corrupted top size). Beyond denial of service, the advisory confirms that with two addresses leaked from a separate information disclosure bug, the heap overflow has been developed into full remote code execution against a stock build with ASLR/PIE/NX enabled — demonstrated by executing an attacker-chosen shell command from within a single-process HTTP server doing nothing but Image.open(BytesIO(body)).save(BytesIO(), 'TIFF') per upload. The stale-heap disclosure independently leaks one byte of freed heap memory per alignment gap in any compressed TIFF output over 64 KiB, exposing data from prior requests at predictable offsets in the returned file (GitHub Advisory).

Exploitability

A proof-of-concept reproducer is publicly available in the GitHub Security Advisory, including a hand-built 131,198-byte PackBits TIFF (mode L, 7×8191, 65,535-character ImageDescription) that crashes a stock Pillow build when saved to io.BytesIO(). The advisory also describes (but withholds) a full code-execution chain demonstrated against a stock build with ASLR/PIE/NX. The vulnerability is not yet listed in the CISA KEV catalog, and the EPSS score is 0.0 at time of publication, indicating no confirmed in-the-wild exploitation. No specific threat actor attribution is available (GitHub Advisory, Feedly).

Exploitation steps

  1. Craft the malicious TIFF: Build a single-band (mode L) compressed TIFF (~131 KB) with PackBits compression, dimensions 7×8191, and a 65,535-character ImageDescription tag. The pixel rows are chosen so the re-encoded PackBits strip is exactly 65,536 bytes (8 bytes/row × 8,191 rows + 8-byte header), ending precisely at the sink's initial 64 KiB buffer boundary.
  2. Deliver to target service: Upload the crafted TIFF to any service that accepts image uploads and re-saves them as TIFF to an in-memory buffer (e.g., io.BytesIO) — the common pattern for returning or uploading results without touching disk.
  3. Trigger the vulnerable code path: The service calls Image.open(upload).save(io.BytesIO(), 'TIFF') with no special options. Compression and tags are inherited from the source, selecting the libtiff writer and the _tiffWriteProc memory sink (since the target has no fileno()).
  4. Overflow occurs: libtiff seeks past the 126-byte IFD to offset 65,662 and writes the 65,536-byte ImageDescription. _tiffWriteProc grows the buffer only to 131,072 bytes, so the last 126 bytes of the description are written past the end of the heap block, corrupting adjacent heap metadata.
  5. Denial of service / code execution: On a stock build, glibc detects the corruption and kills the process with SIGABRT. With two leaked addresses (e.g., &system, &PyBytes_Type from a separate info-disclosure bug), the overflow can be shaped to overwrite a libtiff cleanup function pointer (tif_cleanup = system) and execute an attacker-chosen shell command when libtiff calls (*tif->tif_cleanup)(tif) during TIFFFlush (GitHub Advisory).

Indicators of compromise

  • Process: Worker process (Python/Pillow) terminating unexpectedly with SIGABRT or exit code -6; glibc error message malloc(): corrupted top size in stderr logs.
  • Logs: Application logs showing crashes or unhandled exceptions during TIFF save operations, particularly when saving to in-memory buffers; TIFFError messages referencing _tiffWriteProc with invalid write locations.
  • File System: Unexpected files in /tmp/ (e.g., r.XXXXXX pattern) created by the Pillow worker process, which may indicate successful command execution via the code-execution chain.
  • Network: Repeated upload requests containing large TIFF files (~131 KB) with single-band (mode L) images and unusually long ImageDescription or DocumentName tags (≥64 KiB); responses returning TIFF files with anomalous byte differences at predictable offsets (stale heap disclosure).
  • Output Files: Returned TIFF files where bytes at alignment-gap offsets (between odd-length tag values and before the IFD) contain non-zero values inconsistent with file-based saves — indicative of stale heap byte disclosure (GitHub Advisory).

Mitigation and workarounds

Upgrade Pillow to version 13.0.0 or later, which fixes the bug by changing _tiffWriteProc to size the realloc buffer from the current write position (state->loc) rather than the prior buffer size (state->size), and zeroing newly allocated space to prevent stale-byte disclosure (Pillow 13.0.0 Release, Fix Commit). If immediate patching is not possible, avoid processing untrusted TIFF images with Pillow's save functionality when writing to in-memory file-like objects (BytesIO); saving to a real file path (with a valid fileno()) is unaffected by this vulnerability. Additionally, restrict TIFF file sources to trusted origins only, and consider stripping or sanitizing TIFF tags (especially ImageDescription, DocumentName, XMP, and ICC profiles) before re-encoding uploads (GitHub Advisory).

Community reactions

The vulnerability was reported by researchers credited as carlini and Tomer-PL in the GitHub Security Advisory, which includes an unusually detailed technical write-up with a full reproducer script, code walk-through, and description of a working (withheld) code-execution chain. The advisory notes that the defect class is the same as prior Pillow TiffDecode.c heap overflows (CVE-2020-35654, CVE-2021-25289, CVE-2020-10379), but on the encode path. The Pillow maintainers responded promptly with a fix merged in PR #10224 and released in version 13.0.0 (GitHub Advisory, Pillow 13.0.0 Release).

Additional resources

Linux Distribution fix status

Fix availability across major Linux distributions and their releases.

Debian

Fixed

bookworm

pillow

Affected

sid

pillow: 13.0.0-1

Fixed

trixie

pillow

Affected

Ubuntu

Unknown

bionic (esm-infra)

pillow

Unknown

devel

pillow

Unknown

focal (esm-apps)

pillow-python2

Unknown

focal (esm-infra)

pillow

Unknown

jammy

pillow

Unknown

noble

pillow

Unknown

resolute

pillow

Unknown

trusty (esm-infra-legacy)

pillow

Unknown

Source: This report was generated using AI

Related Python vulnerabilities:

CVE ID

Severity

Score

Technologies

Component name

CISA KEV exploit

Has fix

Published date

GHSA-mpqx-q82w-9x46HIGH7.5
  • Python logoPython
  • graphql-core
NoYesOct 25, 2026
GHSA-4gm2-62xx-xwvxMEDIUM5.3
  • Python logoPython
  • aynops
NoYesOct 25, 2026
GHSA-jm75-qwf5-vg52MEDIUMN/A
  • Python logoPython
  • exmergo-dex-core
NoYesOct 25, 2026
GHSA-f3jf-cv9h-7c3gHIGHN/A
  • Python logoPython
  • exmergo-dex-core
NoYesOct 25, 2026
GHSA-28xv-9wpg-c42rHIGHN/A
  • Python logoPython
  • exmergo-dex-core
NoYesOct 25, 2026

Free Vulnerability Assessment

Benchmark your Cloud Security Posture

Evaluate your cloud security practices across 9 security domains to benchmark your risk level and identify gaps in your defenses.

Request assessment

Additional Wiz resources

Get a personalized demo

Ready to see Wiz in action?

"Best User Experience I have ever seen, provides full visibility to cloud workloads."
David EstlickCISO
"Wiz provides a single pane of glass to see what is going on in our cloud environments."
Adam FletcherChief Security Officer
"We know that if Wiz identifies something as critical, it actually is."
Greg PoniatowskiHead of Threat and Vulnerability Management