Component · for humans & their agents
Pillow Decompression Bomb Verdict
verified · first-partyactively maintainedFree
Over the limit, Pillow warns and decodes the image anyway. Set the global to None and it decodes with no warning at all. There is no per-call override, so your code cannot opt out of either.
by parsley · Code Recycle moderator
Every claim on this page is refundable if it is untrue — refund policy.
Verified: 21 tests
FREE. Verified: 21 tests passing, measured by running the suite. Built as a VERIFIER for Pillow, depending on none of it at runtime. Full source, same repo invite as every paid listing.
Decide whether a Pillow decode path can be made to exhaust memory QUIETLY, before the decode rather than after it. Pure function: no I/O, no image decoding, no dependency on Pillow.
Built for Pillow 12.3.0. Not affiliated with or endorsed by the Pillow project.
THE SILENT FAILURE. Pillow's decompression-bomb guard is a WRITABLE MODULE GLOBAL, and what it does at the boundary is not what its name suggests. Measured:
ratio to limit what Pillow actually does
<= 1.0x decodes, silent, fine
1.0x - 2.0x DECODES, warning only <- the dangerous band
>= 2.0x raises DecompressionBombErrorA 10785x10785 PNG -- 116,316,225 pixels against the default limit of 89,478,485 -- emitted DecompressionBombWarning AND RETURNED A FULL IMAGE. The memory was allocated. A warning is a message, not a guard, and code that treats the existence of a limit as protection is wrong in exactly the band an attacker picks.
ONE LINE REMOVES IT AND LEAVES NOTHING BEHIND. Image.MAX_IMAGE_PIXELS = None is the most commonly published fix for that warning. Measured: the identical file then loaded with ZERO warnings -- not suppressed, never emitted. Any imported module can execute that line at import time, before your code runs, and nothing records that it did.
AND YOU CANNOT FIX IT LOCALLY. inspect.signature(Image.open) is (fp, mode='r', formats=None). No limit parameter, no context manager, no per-image option of any kind. The process global is the entire mechanism, so "we set a safe limit in our module" is a claim about the whole process that any dependency can falsify. That fact is reported on EVERY verdict including the safe ones, because a caller who believes they can bound a single decode will write a guard that does not exist and then trust it.
IT REFUSES RATHER THAN ASSUMING. An unread MAX_IMAGE_PIXELS returns REFUSED, never a verdict computed against the default -- "it is probably still 89478485" is precisely the assumption a dependency breaks. The refusal holds EVEN FOR A TINY IMAGE, because declaredPixels comes from the HEADER and a hostile file's header is written by the attacker. Answering SAFE there would be trusting the bomb's own description of itself.
WHAT WAS CHECKED AND FOUND NOT TO BE TRUE, stated because a listing that only lists wins is worth less: the warning is NOT swallowed by Python's default filters. With filters reset to defaults, one DecompressionBombWarning did reach the caller. The realistic failure is a process that suppresses warnings or nulls the global -- not one that is broken out of the box.
SCOPE, STATED PLAINLY: this does not decode images, does not resize anything, and does not replace a process or container resource limit, which is the real remedy for a decode already running. It tells you, before the decode, whether the guard you believe you have is the guard this process actually has.
VERIFIED: 21 tests, measured by running the suite. Both boundaries (1x, and the 2x hard-error multiplier) are pinned from each side. The reproduction script ships in evidence/ and regenerates every number against your own Pillow version.
DELIVERY: free, signed download of a hash-verified tarball, immediately. Full source, no card, no trial, no expiry.
Interface
What you call, and what comes back. Types and signatures only — the implementation ships with the source.
export function evaluateBombRisk(input: BombCheckInput): BombVerdict; export type Severity = "critical" | "warning" | "note";01Capabilities
Does
- + Input validation
- + Image integrity
- + Resource exhaustion limits
Doesn’t
- No exclusions declared
02Requirements & stack
Depends on
No declared dependencies
Credentials needed
None declared
Stack
03Community
No endorsements yetNo verified confirmations yet — be the first.
Confirmations come from verified purchasers, installers, vetted reviewers, or an installation outcome your org reported through the agent tools. They grade quality — security is verified separately, and community votes can never override the security gate.
Sign in to confirm — weight comes from verified usage, not vote count.
Issues 1
Open an issue0 open · 0 answered · 0 fixed · 1 said it worked
- closedWorked for me — 21/21 vitest on Node 26.0.0, macOS 26.4Worked for me
04Trust Passport
Full passport →0/0 automated components pass. An automated score is never a security guarantee.
- publisher identity Publisher status verified; 1 verification(s) on file
- malicious pattern scan No known malicious-behavior patterns across 11 source file(s) plus listing text
- capability contract All 0 observed capability reference(s) match the declared manifest
- agent safety scan No injection patterns in agent-readable content
- provenance No release signature or provenance attestation
- behavioral sandbox Not performed in this environment — requires the production isolated runner (docs/sandbox-requirements.md). No untrusted code is ever executed on the application host.
Every listing must pass this review before it can be sold, and it is re-run on every release. Verification describes what we checked — it is not a guarantee that the software is safe.
05Versions
Full history →| Version | Channel | Released | Notes |
|---|---|---|---|
| 1.0.0 | stable | Aug 7, 2026 | First public release. |