fix(uploads): bound image decode with explicit Limits, closing the unbounded GIF path [operator-action] (LC-206-IMAGE-LIMITS) #288
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/lc-206-image-limits"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #284 (LC-206-IMAGE-LIMITS). Filed investigate-first; the spike confirmed a real unbounded-decode path, so this applies the fix.
Investigation result
image0.25.10Limits::default()caps still-imagemax_allocat 512 MiB, BUTGifDecoder::newinitialisesLimits::no_limits()- the GIF decode path inuploads::pipelinewas unbounded.THUMBNAIL_CONCURRENCY(4) is ~2 GiB transient on a burst, and the bound was an implicit crate default. A spike comment in-tree already wrongly asserted "image 0.25 has no default Limits" - the kind of stale assumption a version bump silently breaks.Fix
A shared
decode_limits()(256 MiBmax_alloc+ 16384 dimension caps) is applied at every decode site inpipeline.rs:ImageReader::limits()on the two still paths,GifDecoder::set_limits()on the GIF path. 256 MiB admits a ~64 MP RGBA image (covers real photos under the 10 MiB cap) while rejecting bombs; the bound no longer depends on the image-crate default, and the GIF hole is closed. The LC-206 grep-ban already forces all decoders throughpipeline.rs, so coverage is structural.Tests
uploads_pipeline.rs:png_decompression_bomb_rejected_by_limits: a VALID 12000x12000 PNG (~410 KB on disk, under the 10 MiB byte cap; ~432 MB decoded) is rejected specifically asPipelineError::Decode(ImageError::Limits(_))- asserting the LIMIT fires, not malformedness.constant_png_builder_produces_a_decodable_image: the same builder at 8x8 decodes fine, proving the bomb fixture is well-formed (so the rejection is the limit, not a broken file).set_limitsdoes not break legit GIFs.The stale spike comment is corrected; CLAUDE.md gains an "Image decoders need explicit Limits" gotcha.
flate2added as a dev-dependency (already in-tree transitively) to stream the bomb fixture's zero scanlines without materialising 432 MB.Validation
just test+just test-saas+just checkall green (both modes clippy-D warnings, fmt, desktop).Operator action
Security fix present in shipped versions - upgrade promptly. An attacker-supplied GIF decompression/animation bomb fetched via the foreign-avatar proxy (or uploaded) could exhaust server memory and crash the process. No configuration change required; the fix is the explicit decode
Limitsin this release.🤖 Generated with Claude Code