VLLM · GHSA-vxqj-p4gw-9h4c · AI agents & MCP
FIX → 0.31.0
A client of a vLLM server can send a request-level num_frames of -1 that overrides the server's video frame cap, so every JPEG frame in a video payload is decoded. Memory use then grows with the number of frames supplied, which can exhaust memory on the server.
first public Oct 27, 2026 · 1 source
Could this affect your app?
Free first check from your website. Connect your repo for the full answer.
Servers running vLLM 0.19.0 through 0.27.1 (or main before the fix) that accept video requests from clients through the chat completions endpoint are exposed. Deployments that only serve text models, or that are reachable only by trusted callers behind an API key, have a smaller exposure. Teams that already run vLLM 0.31.0 or later are not affected.
Not affected if auth-required, text-only-models, trust-request-mm-kwargs-disabled
Who cares llm-serving, python, self-hosted, vllm
pip show vllm and compare it against the affected range >= 0.19.0, < 0.31.0./v1/chat/completions.--api-key is set; without it, the route has no API-key middleware.--trust-request-mm-kwargs is enabled, since the advisory says it restores trusted override behavior.The frame-count protection added by PR #38636 for GHSA-pq5c-rjhq-qp7p / CVE-2026-34755 is incomplete in vLLM v0.19.0 through v0.27.1 and current main at commit 6c95a641e95c0faa6f3aa802d1fd3cce3f3bc3ce.
An inference client can set media_io_kwargs.video.num_frames=-1 in a stock ChatCompletionRequest. The production merge lets that request value replace the engine-level frame setting. VideoMediaIO.load_base64("video/jpeg", ...) treats a negative value as unlimited and decodes every comma-separated JPEG frame before combining them with np.stack.
In a safe exact-path reproduction, the same 256-frame payload loaded 8 frames when the server value was 8, but all 256 frames when the request supplied -1. This restores request-controlled, linearly scalable memory allocation at the same decoder addressed by the parent advisory. I assess the issue as Moderate (CVSS 3.1: 6.5). The safe run demonstrates the limit bypass and allocation growth; it does not claim a reproduced service crash or RCE.
The request field is exposed without a numeric security bound in . performs the engine/request merge (), and the base merge gives runtime values precedence ().
Check it with your coding agent
It reads this page and tells you if your code is affected.
Are you affected?
Ask from here. InfraStack checks the affected versions against your stack and answers in your inbox.
InfraStack checks the affected versions against your stack and answers in Slack, with the evidence and the fix.
Upgrade to 0.31.0
0.31.0--trust-request-mm-kwargs disabled for untrusted clients (per the advisory, PR #58830 blocks untrusted per-request media kwargs by default)ChatCompletionRequestChatParams.with_defaults()VideoMediaIO.merge_kwargs() removes unsafe request-level GPU backend settings but does not reject or clamp num_frames (media/video.py). The resulting value reaches the following decoder branch (media/video.py):
if self.num_frames > 0:
frame_parts = data.split(",", self.num_frames)[: self.num_frames]
elif self.num_frames == 0:
raise ValueError("num_frames must be greater than 0 or -1")
else:
frame_parts = data.split(",")
frames = np.stack(
[np.asarray(load_frame(frame_data)) for frame_data in frame_parts]
)
The effective policy is therefore:
server value: {"video": {"num_frames": 8}}
request value: {"video": {"num_frames": -1}}
effective: {"video": {"num_frames": -1}}
The source-traced actor-to-sink chain is:
POST /v1/chat/completions
-> ChatCompletionRequest.media_io_kwargs
-> ChatCompletionRequest.build_chat_params()
-> ChatParams.with_defaults()
-> merge_media_io_kwargs() / VideoMediaIO.merge_kwargs()
-> MediaConnector data-URL handling
-> VideoMediaIO.load_base64("video/jpeg", ...)
-> all-frame JPEG decode and np.stack
The -1 sentinel is an intentional “all frames” sampling preference and was shown in the runtime API example for PR #34778. PR #38636 also retained a negative-value unlimited test. This report does not claim that the sentinel itself is new. The security issue is the absence of a trust separation between an operator preference and the server-side ceiling introduced to remediate GHSA-pq5c. A low-privilege request can disable that ceiling. A very large positive request value has the same policy problem because the client selects the effective maximum.
VLLM_MAX_IMAGE_PIXELS applies independently to each JPEG and does not bound aggregate frames or decoded pixels. Downstream model limits run after media loading and cannot prevent the split, per-frame allocations, and combined stack.
The report confirmed this behavior in v0.27.1 (6e448d0ea9bf3d88d898b65449ca6dc2aec170ac) and the then-current main revision. The online request-boundary fix is available in v0.31.0.
The recommended fix is a positive server-enforced maximum frame or aggregate decoded-work budget that is independent of request and startup sampling preferences. On the online API, request num_frames <= 0 and values above the maximum should be rejected or mapped to the server limit.
This is an availability/resource-exhaustion issue affecting deployments that expose a video-capable multimodal model to inference clients. An actor who can submit a video request can replace the operator's frame setting with -1 or an attacker-selected large value. Memory consumption then scales with every supplied frame, including individual decoded frame arrays and the combined np.stack allocation.
If --api-key is configured, the actor needs a valid inference API key. Without a configured key, the stock /v1/chat/completions route has no API-key middleware. I retain the parent advisory's conservative PR:L vector.
In a memory-constrained deployment, a sufficiently large request can cause allocation failure or API/renderer process termination through container or host OOM handling. The retained safe run does not itself demonstrate a service crash. No confidentiality, integrity, or code-execution impact is claimed.
vllm (PyPI).>= 0.19.0, < 0.31.0.0.31.0.PR #58830 blocks untrusted per-request mm_processor_kwargs and media_io_kwargs by default before preprocessing. Keep --trust-request-mm-kwargs disabled for untrusted clients. Explicitly enabling it restores trusted override behavior; the underlying processor/sampler is not independently bounded by this fix.
Advisory fixed in #58830.