[Security] Restrict Pillow image formats on untrusted media paths by jperezdealgaba · Pull Request #60022 · vllm-project/vllm · GitHub
Skip to content

[Security] Restrict Pillow image formats on untrusted media paths - #60022

Merged
DarkLight1337 merged 2 commits into
vllm-project:mainfrom
jperezdealgaba:fix/restrict-pillow-image-open-formats
Oct 5, 2026
Merged

DarkLight1337 merged 2 commits into
vllm-project:mainfrom
jperezdealgaba:fix/restrict-pillow-image-open-formats

Conversation

@jperezdealgaba

Copy link
Copy Markdown
Contributor

Summary

Untrusted image bytes were passed to Pillow without a format allowlist, so PostScript/EPS payloads could be dispatched to an external renderer during multimodal media loading. This change opens images only with an explicit raster-format allowlist on the shared media loader and the Kimi fused-vision path that also opens raw bytes.

Changes

  • vllm/multimodal/image.py: add ALLOWED_IMAGE_FORMATS (Pillow Image.OPEN audit: allow native in-process readers; deny EPS, WMF, stub drivers, MPEG) and open_image().
  • vllm/multimodal/media/image.py: use open_image() in ImageMediaIO.load_bytes().
  • vllm/transformers_utils/processors/kimi_k25_vision_fused.py: use open_image() in _to_pil() (module-scope import).
  • tests/multimodal/media/test_image.py: reject PostScript payloads; keep common raster formats accepted; assert denied plugins stay off the allowlist; assert open_image has no formats override.

Codepath coverage

  • OpenAI/Anthropic multimodal chat image fetch via MediaConnector → ImageMediaIO.load_bytes / load_base64 / load_file: covered.
  • Async image fetch and media-cache decode through the same ImageMediaIO methods: covered.
  • video/jpeg frame decoding that reuses ImageMediaIO: covered.
  • Kimi fused vision _to_pil raw bytes / data-URL / path opens: covered.
  • Inkling / dots3 JPEG round-trips that reopen self-encoded raster bytes: not client sinks for this control.

Duplicate-work check

Searched open and merged PRs for ImageMediaIO, open_image, ALLOWED_IMAGE_FORMATS, and Pillow formats= allowlist wording. No open or merged PR adds a Pillow formats= allowlist on untrusted image opens.

Tests

  • test_image_media_io_rejects_postscript_payload
  • test_image_media_io_accepts_common_raster_formats
  • test_allowed_image_formats_exclude_external_renderer_plugins
  • test_kimi_fused_vision_rejects_postscript_payload
  • test_open_image_does_not_accept_format_override

Commands:

PYTHONPATH=. .venv/bin/python -m pytest \
  tests/multimodal/media/test_image.py::test_image_media_io_rejects_postscript_payload \
  tests/multimodal/media/test_image.py::test_image_media_io_accepts_common_raster_formats \
  tests/multimodal/media/test_image.py::test_allowed_image_formats_exclude_external_renderer_plugins \
  tests/multimodal/media/test_image.py::test_kimi_fused_vision_rejects_postscript_payload \
  tests/multimodal/media/test_image.py::test_open_image_does_not_accept_format_override \
  -v --noconftest

All passed. pre-commit run --files on the touched paths passed.

AI assistance

This PR was developed with AI assistance.

Made with Cursor

Open untrusted multimodal image bytes only with an audited Pillow format
allowlist so PostScript/EPS payloads cannot reach external renderers.
Cover ImageMediaIO and the Kimi fused-vision path, and add regression
tests for rejected and accepted formats.

Co-authored-by: Cursor Agent
Signed-off-by: Juan Pérez de Algaba <jperezde@redhat.com>

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@mergify mergify Bot added rust multi-modality Related to multi-modality (#4194) kimi labels Oct 5, 2026
@DarkLight1337

Copy link
Copy Markdown
Member

@jperezdealgaba

Copy link
Copy Markdown
Contributor Author

@DarkLight1337 This MR is the public version of the one you just reviewed privately

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

@DarkLight1337 DarkLight1337 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, just double checking using AI. LGTM

@DarkLight1337
DarkLight1337 enabled auto-merge (squash) October 5, 2026 07:38
@DarkLight1337

Copy link
Copy Markdown
Member

/ci run --allow-stale

@github-actions github-actions Bot added the ready ONLY add when PR is ready to merge/full CI is needed label Oct 5, 2026
@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

✅ Triggered Buildkite CI #92844 for commit 635ea7ef7e59.

@vllm-agent

vllm-agent commented Oct 5, 2026 •

Copy link
Copy Markdown
Collaborator

CI selector (shadow): 20 test steps (46 jobs) instead of 57 (73 jobs)

Shadow mode: this changes nothing about what CI runs. It shows what the evidence-based selector would pick for this PR, next to today's rules. How it works.

Feedback welcome: reply here if it would skip a step this change needs, or runs something unrelated.

steps (jobs) Today's rules Selector Would skip Would add
NVIDIA, CPU and others 57 (73) 20 (46) 43 (51) 6 (24)
AMD mirrors 49 (60) 13 (29) 39 (47) 3 (16)
Selector would run (20)
  • arm-cpu-test ×3
  • async-engine-inputs-utils-worker
  • basic-models-tests-extra-initialization ×14
  • benchmarks-cli-test
  • cpu-language-generation-and-pooling-model-tests ×3
  • cpu-multi-modal-model-tests-n ×4
  • cpu-multimodal-config
  • cpu-reasoning-renderers
  • cpu-spec-decode-tests
  • entrypoints-integration-api-server ×4
  • entrypoints-integration-api-server-openai-chat_completion
  • entrypoints-integration-multimodal
  • entrypoints-integration-pooling
  • entrypoints-unit-tests
  • examples
  • mooncake-ec-tcp-e2e-2-gpus
  • multi-modal-models-standard-4-other-whisper
  • multi-modal-processor-cpu ×4
  • pytorch-compilation-unit-tests-h100
  • scale-out-ec-e2e-2-gpus
Would skip (today's rules run them) (43)
  • ascend-npu-test
  • basic-correctness ×2
  • basic-correctness-cpu-offload
  • basic-correctness-cumem
  • basic-correctness-prefetch-offload
  • basic-correctness-sleep-mode
  • basic-models-test-other-cpu
  • basic-models-tests-initialization
  • basic-models-tests-other
  • cpu-params-env-tokenizers-parser
  • cpu-tool-parsers
  • entrypoints-integration-api-server-generate
  • entrypoints-integration-api-server-openai-completion
  • entrypoints-integration-llm
  • entrypoints-integration-responses-api
  • entrypoints-integration-speech_to_text
  • kernels-fla-ops-test-b200
  • kernels-mhc-test-b200
  • kernels-root-misc-test-b200
  • language-models-tests-granite-l4-compatibility
  • language-models-tests-hybrid ×2
  • language-models-tests-standard
  • metrics-tracing-2-gpus
  • multi-modal-accuracy-eval-small-models
  • multi-modal-models-standard-1-qwen2
  • multi-modal-models-standard-2-qwen3-gemma
  • multi-modal-models-standard-3-llava-qwen2-vl
  • multi-modal-processor ×4
  • pytorch-compilation-dynamic-shapes
  • pytorch-compilation-passes-unit-tests
  • pytorch-compilation-unit-tests
  • pytorch-fullgraph-cudagraph-l4-compatibility
  • pytorch-fullgraph-test
  • regression
  • v1-core
  • v1-executor-worker
  • v1-kv-connectors ×4
  • v1-kv-offload
  • v1-logits-oracle
  • v1-metrics-lmeval
  • v1-others-cpu
  • v1-sample
  • v1-spec-decode
Would add (today's rules do not run them) (6)
  • arm-cpu-test ×3 (code map)
  • basic-models-tests-extra-initialization ×14 (code map)
  • cpu-multi-modal-model-tests-n ×4 (code map)
  • cpu-spec-decode-tests (code map)
  • entrypoints-unit-tests (code map)
  • scale-out-ec-e2e-2-gpus (Python record)
AMD mirrors: would skip (39)
  • basic-correctness ×2
  • basic-correctness-cpu-offload
  • basic-correctness-cumem
  • basic-correctness-prefetch-offload
  • basic-correctness-sleep-mode
  • basic-models-tests-initialization
  • basic-models-tests-other
  • entrypoints-integration-api-server-generate
  • entrypoints-integration-api-server-openai-completion
  • entrypoints-integration-llm
  • entrypoints-integration-responses-api
  • entrypoints-integration-speech_to_text
  • kernels-fla-ops-test-b200
  • kernels-mhc-test-b200
  • kernels-root-misc-test-b200
  • language-models-tests-granite-l4-compatibility
  • language-models-tests-hybrid ×2
  • language-models-tests-standard
  • metrics-tracing-2-gpus
  • multi-modal-accuracy-eval-small-models
  • multi-modal-models-standard-1-qwen2
  • multi-modal-models-standard-2-qwen3-gemma
  • multi-modal-models-standard-3-llava-qwen2-vl
  • multi-modal-processor ×4
  • platform-tests
  • pytorch-compilation-dynamic-shapes
  • pytorch-compilation-passes-unit-tests
  • pytorch-compilation-unit-tests
  • pytorch-fullgraph-cudagraph-l4-compatibility
  • pytorch-fullgraph-test
  • regression
  • v1-core
  • v1-executor-worker
  • v1-kv-connectors ×4
  • v1-kv-offload
  • v1-logits-oracle
  • v1-metrics-lmeval
  • v1-sample
  • v1-spec-decode
AMD mirrors: would add (3)
  • basic-models-tests-extra-initialization ×14 (code map)
  • entrypoints-unit-tests (code map)
  • scale-out-ec-e2e-2-gpus (Python record)

4 changed files · base 4a30c4cad0 · head 8d997a21aa · Python record: build 92817 at 7867d6c52d · kernel record: table 7867d6c (build 92817), map 7867d6c · not counted: 10 build steps, 5 A100 steps the generator no longer emits, 13 optional steps the selector would also run

@DarkLight1337

Copy link
Copy Markdown
Member

/ci retry

@github-actions

github-actions Bot commented Oct 5, 2026

Copy link
Copy Markdown

@DarkLight1337
DarkLight1337 merged commit 710ac56 into vllm-project:main Oct 5, 2026
17 checks passed
michael-gpu pushed a commit to practical-inference/vllm-ampere-extended that referenced this pull request Oct 20, 2026
…lm-project#60022)

Signed-off-by: Juan Pérez de Algaba <jperezde@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kimi multi-modality Related to multi-modality (#4194) ready ONLY add when PR is ready to merge/full CI is needed rust

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants