Listen to this Post
Pillow suffers from an out-of-bounds heap memory read vulnerability within its TIFF decoding implementation located in src/libImaging/TiffDecode.c. Specifically, functions such as _decodeTile() and _decodeAsRGBA() allocate their internal decoding buffers based strictly on libtiff’s calculated pixel dimensions and strip/tile sizes. However, they subsequently unpack each row using a shuffler selected by Pillow’s own independent image file directory (IFD) parser. Discrepancies between libtiff’s parser and Pillow’s parser—which can be triggered via malformed files containing duplicate or incorrectly counted tags like PhotometricInterpretation or BitsPerSample—cause the unpacker to expect and read wider rows than libtiff actually produces and writes into the buffer. Consequently, the unpacker reads past the end of the allocated heap buffer, and these leaked bytes are copied directly into the pixel data of the returned image object. An attacker can exploit this behavior by uploading specially crafted compressed TIFF files to target applications that process images into thumbnails, previews, or converted formats, thereby recovering sensitive fragments of adjacent heap memory, including pointer values and allocator states. In certain configurations involving excessively wide tiles, the out-of-bounds read leads directly to an application segmentation fault and denial of service. The vulnerability stems from a missing boundary check comparing the unpacker’s calculated row size against the actual row size provided by libtiff, a check that was previously implemented for strip paths but omitted from tile and RGBA decoding paths.
DailyCVE Form:
Platform: Python
Version: Pillow < 8.3.2
Vulnerability : OOB read
Severity: Critical
date: 2026-10-21
Prediction: 2021-07-01
What Undercode Say:
The vulnerability arises due to a fundamental parsing discrepancy between libtiff and Pillow’s Python-based IFD parser. When libtiff encounters duplicate tags or invalid counts, it typically retains the first occurrence or ignores the tag entirely, whereas Pillow’s loader overwrites parameters and retains the final occurrence. This desynchronization results in mismatched buffer allocation sizes versus unpacking strides.
Exploit: (Educational Purposes!)
import zlib, struct, tempfile
def create_malformed_tiff():
d = zlib.compress(bytes(range(256)) 3)
Constructing a TIFF file with conflicting tag counts to trigger parser disagreement
header = b"II\0" + struct.pack("<L", 8)
return header
Protection:
Upgrade Pillow to version 8.3.2 or later where the missing row-size validation checks (unpacker_row_byte_size > row_byte_size) have been properly restored across both `_decodeTile()` and _decodeAsRGBA().
Impact:
Attackers can cause unauthorized disclosure of sensitive heap memory contents, including application pointers, via standard image processing pipelines, or trigger process crashes leading to denial of service.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

