For images you trust, raise the limit before opening: Image.MAX_IMAGE_PIXELS = 250_000_000 (or
None to disable it). For images from users, keep the limit and reject anything larger; that is exactly the attack
it prevents.
The two thresholds
from PIL import Image
print("warning above:", f"{Image.MAX_IMAGE_PIXELS:,}", "pixels")
print("error above: ", f"{2 * Image.MAX_IMAGE_PIXELS:,}", "pixels")
for w, h in [(6000, 4000), (10000, 10000), (14000, 14000)]:
print(f"{w} x {h} = {w * h:>11,} pixels")
warning above: 89,478,485 pixels
error above: 178,956,970 pixels
6000 x 4000 = 24,000,000 pixels
10000 x 10000 = 100,000,000 pixels
14000 x 14000 = 196,000,000 pixels
Above 89.5 megapixels Pillow emits a DecompressionBombWarning but carries on. Above twice that it raises
DecompressionBombError and refuses. A 24-megapixel camera photo is nowhere near either; scanned maps, panoramas,
microscopy and satellite images can be.
What it looks like
A 100-megapixel PNG of a single colour compresses to a tiny file but would need 100 MB of RAM to decode:
import os
import warnings
from PIL import Image
print("huge.png on disk:", os.path.getsize("huge.png") // 1024, "KB")
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
img = Image.open("huge.png")
print(caught[0].category.__name__ + ":", caught[0].message)
huge.png on disk: 94 KB
DecompressionBombWarning: Image size (100000000 pixels) exceeds limit of 89478485 pixels, could be decompression bomb DOS attack.
Above the second threshold, open() itself fails:
import os
from PIL import Image
print("bomb.png on disk:", os.path.getsize("bomb.png") // 1024, "KB")
Image.open("bomb.png")
bomb.png on disk: 185 KB
Traceback (most recent call last):
...
PIL.Image.DecompressionBombError: Image size (196000000 pixels) exceeds limit of 178956970 pixels, could be decompression bomb DOS attack.
The check runs on the size declared in the header, so the attack is stopped before any memory is allocated.
Raise or disable the limit (trusted images)
from PIL import Image
Image.MAX_IMAGE_PIXELS = 250_000_000 # trusted input only; set before opening
img = Image.open("bomb.png")
print("opened", img.size, "-", f"{img.width * img.height:,}", "pixels")
opened (14000, 14000) - 196,000,000 pixels
The setting is global for the whole process. In a long-running app that also handles uploads, change it only around the trusted work:
import contextlib
from PIL import Image
@contextlib.contextmanager
def pixel_limit(limit):
"""Temporarily change Pillow's limit, e.g. for one trusted batch job."""
old = Image.MAX_IMAGE_PIXELS
Image.MAX_IMAGE_PIXELS = limit
try:
yield
finally:
Image.MAX_IMAGE_PIXELS = old
with pixel_limit(None): # None disables the check entirely
print(Image.open("bomb.png").size)
print("limit restored:", f"{Image.MAX_IMAGE_PIXELS:,}")
(14000, 14000)
limit restored: 89,478,485
Or avoid decoding the full image at all
If you only need a preview of a huge JPEG, ask the decoder to scale down while decoding. It is much faster and uses a fraction of the memory:
import time
from PIL import Image
Image.open("photo.jpg").resize((9600, 6400)).save("scan.jpg", quality=90) # 61 megapixels
t = time.perf_counter()
img = Image.open("scan.jpg")
img.draft("RGB", (1200, 800)) # JPEG only: decode at 1/2, 1/4 or 1/8 scale
img.load()
print("draft load:", img.size, f"{(time.perf_counter() - t) * 1000:.0f} ms")
t = time.perf_counter()
full = Image.open("scan.jpg"); full.load()
print("full load: ", full.size, f"{(time.perf_counter() - t) * 1000:.0f} ms")
draft load: (1200, 800) 62 ms
full load: (9600, 6400) 301 ms
thumbnail() uses draft mode automatically, which is one reason it is the fastest way to shrink JPEGs
(measured here). For huge TIFFs or PNGs, which have no draft mode,
crop regions with img.crop() after open() or use a tiling library such as pyvips.
Related
The outputs and images on this page are the real results of running every example with Pillow 12.3.0 on Python 3.13 (Linux) on 2026-10-15. Every example is also re-run automatically on macOS (Darwin 25.6.0, Pillow 12.3.0), Linux (Linux 6.17.0-1022-azure, Pillow 12.3.0), Windows (Windows 2025Server, Pillow 12.3.0); the line under each example shows the result per operating system. The DejaVu Sans font files sit next to each script so font examples behave the same everywhere. Sample photos: NASA/Sam Lott, public domain. Spotted something wrong? Tell us.