CVE-2026-112395: Pillow: TIFF tile heap over-read enables DoS and memory leak

GHSA-462x-pgg6-55fpMEDIUM
Published October 20, 2026
CISO Take

Pillow, the Python imaging library behind most image preprocessing in ML pipelines, has a heap over-read in its tiled TIFF decoder. A crafted TIFF makes the decoder read past its allocated buffer, which can crash the process or copy adjacent heap memory into the decoded image. Exposure is wide because the package has about 6,390 tracked downstream dependents and 61 other CVEs on record. Exploitation is currently unlikely: EPSS is 0.00264 (top 83% percentile), the CVE is not in CISA KEV, and there is no public exploit or Nuclei template. The practical risk is any service that decodes untrusted uploaded images, such as vision APIs, multimodal LLM gateways, OCR and document ingestion. Upgrade Pillow to 13.0.0, which fixes the issue in versions >= 8.2.0 and < 13.0.0. Until then, restrict or reject tiled TIFF input from untrusted sources.

Sources:NVDGitHub AdvisoryEPSSATLASOpenSSF

What is the risk?

Medium (CVSS 6.5, AV:N/AC:L/PR:N/UI:N, C:L/A:L). The bug is reachable with no privileges or user interaction wherever an application decodes attacker-supplied TIFFs. Impact is limited to a process crash and a low-confidentiality heap disclosure, and there is no code execution. Likelihood is low for now: EPSS is 0.00264, there is no KEV listing, no public exploit and no scanner template. Exposure is broad because Pillow is a transitive dependency in many AI/ML stacks. The disclosure came from AI-assisted research validated by Ada Logics, and a proof-of-concept TIFF exists in the advisory, so weaponization effort is low for a motivated attacker. Note the 'Affected Products' range (>= 8.2.0, < 13.0.0) is very wide, so most deployed versions are affected.

How does the attack unfold?

Initial Access
The attacker uploads or otherwise supplies a crafted tiled TIFF to an application that decodes images with Pillow.
AML.T0049
Exploitation
The decoder allocates a buffer sized to libtiff's tile size, then strides rows past its end, so the unpacker over-reads about 1 KB of heap per row.
AML.T0010.001
Impact
The worker process crashes, causing denial of service, or adjacent heap memory is copied into the decoded pixel buffer and may be exposed to the requester.
AML.T0029

What systems are affected?

PackageEcosystemVulnerable RangePatched
Anthropic Pythonpip>= 8.2.0, < 13.0.013.0.0
4.0K5.4K dependentsPushed 8d ago93% patched~9d to patchFull package profile →

Do you use Anthropic Python? You're affected.

How severe is it?

CVSS 3.1
6.5 / 10
EPSS
0.5%
chance of exploitation in 30 days
Higher than 44% of all CVEs
Exploitation Status
No known exploitation
Sophistication
Moderate

What is the attack surface?

AVACPRUISCIA
AVNetwork
ACLow
PRNone
UINone
SUnchanged
CLow
INone
ALow

What should I do?

1 step
  1. 1) Upgrade Pillow to 13.0.0 or later (pip install -U 'pillow>=13.0.0') and rebuild container images and lockfiles, including transitive dependencies in vendored environments. 2) Inventory exposure with pip list, SBOM or dependency scanning (pip-audit, GHSA-462x-pgg6-55fp) across inference, ingestion and notebook environments. 3) If you cannot patch immediately, reject TIFF uploads from untrusted sources, or sniff the file header and block tiled TIFFs before decoding. 4) Decode images in isolated, resource-limited worker processes (containers or sandboxes with memory and CPU limits) with automatic restarts, so a crash doesn't cause a service-wide outage. 5) Do not return raw decoded buffers to untrusted callers. 6) Detect: alert on repeated worker segfaults or SIGSEGV/SIGABRT in image-handling services, and on unusual TIFF uploads, particularly tiled TIFFs with 256x256 tiles and unusual photometric or sample layouts.

How is it classified?

Which compliance frameworks are affected?

This CVE is relevant to:

EU AI Act
Article 15-Accuracy, robustness and cybersecurity
ISO 42001
A.10.3-Suppliers
NIST AI RMF
GOVERN 6.1-Policies and procedures for third-party AI risks
OWASP LLM Top 10
LLM03-Supply Chain

Frequently Asked Questions

What is CVE-2026-112395?

Pillow, the Python imaging library behind most image preprocessing in ML pipelines, has a heap over-read in its tiled TIFF decoder. A crafted TIFF makes the decoder read past its allocated buffer, which can crash the process or copy adjacent heap memory into the decoded image. Exposure is wide because the package has about 6,390 tracked downstream dependents and 61 other CVEs on record. Exploitation is currently unlikely: EPSS is 0.00264 (top 83% percentile), the CVE is not in CISA KEV, and there is no public exploit or Nuclei template. The practical risk is any service that decodes untrusted uploaded images, such as vision APIs, multimodal LLM gateways, OCR and document ingestion. Upgrade Pillow to 13.0.0, which fixes the issue in versions >= 8.2.0 and < 13.0.0. Until then, restrict or reject tiled TIFF input from untrusted sources.

Is CVE-2026-112395 actively exploited?

No confirmed active exploitation of CVE-2026-112395 has been reported, but organizations should still patch proactively.

How to fix CVE-2026-112395?

1) Upgrade Pillow to 13.0.0 or later (pip install -U 'pillow>=13.0.0') and rebuild container images and lockfiles, including transitive dependencies in vendored environments. 2) Inventory exposure with pip list, SBOM or dependency scanning (pip-audit, GHSA-462x-pgg6-55fp) across inference, ingestion and notebook environments. 3) If you cannot patch immediately, reject TIFF uploads from untrusted sources, or sniff the file header and block tiled TIFFs before decoding. 4) Decode images in isolated, resource-limited worker processes (containers or sandboxes with memory and CPU limits) with automatic restarts, so a crash doesn't cause a service-wide outage. 5) Do not return raw decoded buffers to untrusted callers. 6) Detect: alert on repeated worker segfaults or SIGSEGV/SIGABRT in image-handling services, and on unusual TIFF uploads, particularly tiled TIFFs with 256x256 tiles and unusual photometric or sample layouts.

What systems are affected by CVE-2026-112395?

This vulnerability affects the following AI/ML architecture patterns: Model serving / inference APIs, Multimodal LLM pipelines, Document and OCR ingestion pipelines, Training data pipelines, Computer vision preprocessing.

What is the CVSS score for CVE-2026-112395?

CVE-2026-112395 has a CVSS v3.1 base score of 6.5 (MEDIUM). The EPSS exploitation probability is 0.51%.

What is the AI security impact?

Affected AI Architectures

Model serving / inference APIsMultimodal LLM pipelinesDocument and OCR ingestion pipelinesTraining data pipelinesComputer vision preprocessing

MITRE ATLAS Techniques

AML.T0010.001AI Software
AML.T0029Denial of AI Service
AML.T0049Exploit Public-Facing Application

Compliance Controls Affected

EU AI Act: Article 15
ISO 42001: A.10.3
NIST AI RMF: GOVERN 6.1
OWASP LLM Top 10: LLM03

What are the technical details?

Original Advisory

### Summary Pillow's libImaging `_decodeTile` decoder, used to decode tiled TIFF images, allocates a per-tile buffer using `realloc(state->buffer, TIFFTileSize(tiff))`. After each `TIFFReadTile` it then iterates `tile_y` from 0 up to `current_tile_length` and calls the configured row unpacker (here `copy4`) with the source pointer `state->buffer + tile_y * row_byte_size`. When libtiff returns a `tile_bytes_size` smaller than the worst-case `row_byte_size * tile_length`, the inner stride-and-copy loop walks past the realloc'd region and `copy4` performs a 1024-byte `memcpy` that reads up to `(tile_length-1) * row_byte_size + row_byte_size` bytes from a buffer sized only to `tile_bytes_size`. The supplied PoC TIFF triggers a 1024-byte over-read exactly 0 bytes past a 196608-byte allocation. An attacker who can convince a Pillow-using application to decode a crafted TIFF can trigger a process crash (DoS) and may cause adjacent heap memory to be copied into the decoded pixel buffer. ### Details Pillow's TIFF decoder, when libtiff reports the file is tiled, takes the `_decodeTile` path. The function: 1. Asks libtiff for `TIFFTileSize(tiff)` (the bytes-per-tile) and `TIFFTileRowSize(tiff)` (the bytes per row *as stored by libtiff*). 2. Reallocates `state->buffer` to exactly `tile_bytes_size`. 3. For each tile origin `(x, y)` and each plane, calls `TIFFReadTile` into `state->buffer`, then walks the tile row by row, calling the configured `ImagingShuffler` (here `copy4`) on each row's worth of source bytes. The validation done before the loop is: ```c if (tile_bytes_size > ((tile_length * state->bits / planes + 7) / 8) * tile_width) { state->errcode = IMAGING_CODEC_BROKEN; return -1; } ``` This rejects oversized libtiff tiles, but it does **not** reject *undersized* ones — i.e. the case where libtiff returns a `tile_bytes_size` strictly **less** than `row_byte_size * tile_length`. The loop body, however, indexes into the buffer assuming the buffer is at least `row_byte_size * tile_length` bytes long. ### Vulnerable Code ```c // src/libImaging/TiffDecode.c:446-490 — _decodeTile new_data = realloc(state->buffer, state->bytes); // bytes = tile_bytes_size if (!new_data) { ... } state->buffer = new_data; for (y = state->yoff; y < state->ysize; y += tile_length) { for (plane = 0; plane < planes; plane++) { ImagingShuffler shuffler = unpackers[plane]; for (x = state->xoff; x < state->xsize; x += tile_width) { if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, plane) == -1) { ... } current_tile_width = min((INT32)tile_width, state->xsize - x); current_tile_length = min((INT32)tile_length, state->ysize - y); for (tile_y = 0; tile_y < current_tile_length; tile_y++) { shuffler( (UINT8 *)im->image[tile_y + y] + x * im->pixelsize, state->buffer + tile_y * row_byte_size, // <-- OOB stride current_tile_width ); } } } } ``` ```c // src/libImaging/Unpack.c:1288-1291 — copy4 (the crash site) static void copy4(UINT8 *out, const UINT8 *in, int pixels) { /* RGBA, CMYK quadruples */ memcpy(out, in, 4 * pixels); // <-- ASAN-detected READ here } ``` The PoC's tile metadata yields `tile_width = tile_length = 256`, `row_byte_size = 1024` (4 bytes/pixel × 256 pixels), and `tile_bytes_size = 196608` (which is 256·256·3 = three-channel-byte storage). The realloc'd buffer is 196608 bytes. The unpacker iterates `tile_y` from 0 to 255 and for the highest rows the source pointer `state->buffer + tile_y * 1024` already lies at or past offset 196608 — the very last row's `memcpy(in=buffer+255·1024, 1024)` reads 1024 bytes starting `260096 - 196608 = 63488` bytes past the allocation; ASAN flags the very first byte past the heap region (`READ of size 1024 at … 0 bytes after 196608-byte region`). The mismatch is real: libtiff's `TIFFTileSize` returns the *packed* per-tile storage (which depends on the file's photometric/separation layout — it can legitimately be smaller than `row_byte_size × tile_length`), while the inner loop strides as if the buffer always equals `row_byte_size × tile_length`. ## Attribution This issue was found by Anthropic from using Claude to study security of open source projects, and I am from Ada Logics helping validate the found issues and report to maintainers. The data in this report has been reviewed manually.

Exploitation Scenario

An attacker finds a public multimodal assistant or document-intelligence API that accepts image uploads and uses Pillow to preprocess them. They submit a crafted tiled TIFF whose tile metadata makes libtiff report a tile size smaller than the row stride multiplied by the tile length (the 256x256 tile case with 4-byte pixels and a 196608-byte buffer). During decoding, the row unpacker copies 1024 bytes per row from past the end of the heap buffer. Repeated uploads crash the worker and degrade or deny the service. In deployments where the processed image or its derived output is returned to the caller, the attacker may also recover fragments of adjacent heap memory, such as parts of other users' images or request data.

Weaknesses (CWE)

CWE-122 — Heap-based Buffer Overflow: A heap overflow condition is a buffer overflow, where the buffer that can be overwritten is allocated in the heap portion of memory, generally meaning that the buffer was allocated using a routine such as malloc().

  • Pre-design: Use a language or compiler that performs automatic bounds checking.
  • [Architecture and Design] Use an abstraction library to abstract away risky APIs. Not a complete solution.

Source: MITRE CWE corpus.

CVSS Vector

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:L

Timeline

Published
October 20, 2026
Last Modified
October 28, 2026
First Seen
October 21, 2026

Related Vulnerabilities