Repository navigation
Guard image decode against oversized (decompression-bomb) images - #28588
Closed
hhhhhhhhhhhhhhhhho wants to merge 1 commit into
Closed
hhhhhhhhhhhhhhhhho wants to merge 1 commit into
hhhhhhhhhhhhhhhhho wants to merge 1 commit into
Conversation
`_load_image` decoded images via `Image.open(BytesIO(...))` with no pixel-count guard. The per-model cap (`SGLANG_IMAGE_MAX_PIXELS` in qwen_vl `smart_resize`) is only applied *after* a full decode, so an oversized image (e.g. a high-DPI rasterized PDF page, or a 12000x12000 PNG) is fully decoded into memory before being downscaled. This pins a CPU core at ~100% for minutes and grows RSS by ~1GB per request; with many concurrent requests it is a pre-inference DoS vector. `Image.open` only reads the header, so width/height are known before the expensive decode. Add `_check_image_pixels` to reject images whose pixel count exceeds `SGLANG_IMAGE_MAX_DECODE_PIXELS` (default = PIL's bomb threshold, 89,478,485; set 0 to disable) right after `Image.open`, before `.convert()` forces the decode. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Closes #28587.
_load_image(python/sglang/srt/utils/common.py) decodes images viaImage.open(BytesIO(...))with no pixel-count guard. The per-model cap (SGLANG_IMAGE_MAX_PIXELS, used bysmart_resizeinqwen_vl.py) is only applied after PIL has fully decoded the image. So an oversized image — e.g. a 300-DPI rasterized PDF page, or a 12000×12000 PNG (144 M px) — is fully decoded into memory (≈ 432 MB RGB buffer) and only then downscaled.Effect on a single Qwen3-VL request with such an image:
With
--max-running-requests 256, concurrent oversized-image requests scale memory linearly and can OOM the server before any GPU inference — a pre-inference DoS vector. vLLM short-circuits the same input via PIL'sDecompressionBombWarning.Note: #27451 truncated the exception message for malformed inputs to 100 chars, which fixed the raw-base64-in-logs / log-flood symptom for the malformed path. It does not help here: a valid oversized image never raises, so the decode cost and memory growth remain. See the issue for the full breakdown.
Modification
_check_image_pixels(width, height)inutils/common.py.Image.openonly reads the header, so width/height are known before the expensive decode (.convert()/.load()). The check rejects images whose pixel count exceeds the limit with a clearValueError, before any pixels are decoded.SGLANG_IMAGE_MAX_DECODE_PIXELS(environ.py), default89_478_485(PIL's default decompression-bomb threshold); set0to disable.test/registered/unit/utils/test_load_image_guard.py) covering within-limit, over-limit, and disabled cases.This intentionally only guards the PIL decode path (the bomb vector). Malformed inputs that fail
Image.openoutright are already handled by #27451.Checklist
CI States
Latest PR Test (Base): ❌ Run #27730377137
Latest PR Test (Extra): ❌ Run #27730376966