VLLM · GHSA-5q78-j82c-2vr2 · AI agents & MCP
FIX → 0.30.0
A reachable assertion in vLLM's GPU model runner aborts the engine when an embeddings-only completion request hits an XD-RoPE model served with prompt embeddings enabled. One unauthenticated request can take down the whole API server, disconnecting every concurrent client.
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.
Deployments that serve an XD-RoPE model, enable --enable-prompt-embeds, and use the V1 model runner are exposed. The advisory states that without --api-key the attack needs no authentication, and with it any authorized caller can trigger it. Servers without XD-RoPE models or without prompt embeds enabled can skip it.
Not affected if no-xdrope-models, prompt-embeds-disabled, version-0.30.0-or-later
Who cares gpu-inference, python, self-hosted, vllm, xd-rope
pip show vllm and compare against the affected range >= 0.28.0, < 0.30.0.rope_scaling.type == "xdrope" (for example tencent/HunyuanOCR).--enable-prompt-embeds.An unauthenticated remote attacker can crash the entire vLLM engine and API server with a single /v1/completions request that contains only prompt_embeds (no prompt text and no prompt_token_ids) when the server runs an XD-RoPE model (HF config with rope_scaling.type == "xdrope", e.g. tencent/HunyuanOCR) with --enable-prompt-embeds on the V1 (MRV1) GPU model runner. The crash is caused by a reachable type-narrowing assert in GPUModelRunner._init_xdrope_positions that is the unpatched XD-RoPE sibling of CVE-2026-55514 / GHSA-33cg-gxv8-3p8g ("vLLM DoS via prompt embeds on M-RoPE models", fixed in v0.24.0 by commit 470229c37): that fix removed the identical assertion from _init_mrope_positions and added a regression test, but the XD-RoPE path was missed and still asserted on main at the time of this report. Verified end-to-end on the released wheel on a real GPU: one attack request makes the whole server process terminate (all concurrent clients disconnected).
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.
VLLM_USE_V2_MODEL_RUNNER=0 or the other configurations listed in the advisory).Upgrade to 0.30.0
vllm 0.30.0 (first stable patched version; the advisory is fixed in PR #56078).vllm==0.28.0Affected code (vllm/v1/worker/gpu_model_runner.py, V1 GPU model runner; lines 1742–1746 in v0.28.0, 1689–1694 in main @ 6f7df92a8):
def _init_xdrope_positions(self, req_state: CachedRequestState):
model = self.get_model()
xdrope_model = cast(SupportsXDRoPE, model)
assert req_state.prompt_token_ids is not None, ( # <- fatal assert
"XD-RoPE requires prompt_token_ids to be available."
)
...
It is invoked for every newly scheduled request whenever the model is detected as XD-RoPE (model_config.uses_xdrope_dim > 0, derived from the HF config fields xdrope_section or rope_scaling.xdrope_section; see vllm/transformers_utils/config.py:580-594):
# update_requests() in gpu_model_runner.py
if self.uses_xdrope_dim > 0:
self._init_xdrope_positions(req_state)
Root cause. The assertion is a mypy type-narrowing guard that is not always true: an embeddings-only request legitimately reaches the worker with prompt_token_ids = None. This is the exact defect described by GHSA-33cg-gxv8-3p8g for the M-RoPE sibling; the June 2026 fix (commit 470229c37, released in v0.24.0) removed the assertion only on the M-RoPE path and its regression test (tests/v1/worker/test_mrope_prompt_embeds.py) covers only M-RoPE.
Why the request reaches the assertion (verified call chain):
vllm/renderers/embed_utils.py:17-38 — safe_load_prompt_embeds validates only tensor shape/dtype (requires the server flag --enable-prompt-embeds), no token ids required.vllm/v1/engine/input_processor.py:343-346 — the "embeds" input type is accepted with prompt_token_ids = None; _validate_model_input imposes no token-id requirement.vllm/v1/request.py:145-146 — embeddings-only requests are first-class (_all_token_ids is a zero-filled placeholder list)._update_states() → update_requests() → _init_xdrope_positions(req_state) raises AssertionError inside the EngineCore execution loop. In the default in-process worker deployment the EngineCore dies; the API server then shuts down, dropping every in-flight request of all tenants.Affected configuration surface. The V1 model runner is selected (and the assertion thus reachable) in many supported configurations, including: VLLM_USE_V2_MODEL_RUNNER=0, environments without Triton, ROCm-specific architectures, --speculative-config "method=ngram_gpu", P-EAGLE parallel drafting, EAGLE3 with pipeline parallelism > 1, PP with external_launcher, sequence parallelism with TP > 1, stock torch.compile, DBO, elastic expert parallelism, custom logits-processor plugins, and KV-sharing fast prefill (selection logic: vllm/config/vllm.py:620-652, 2396-2490).
End-to-end observation (2026-08-28, NVIDIA RTX PRO 6000, vllm==0.28.0 PyPI wheel). Real server log excerpt on a single attack request:
(EngineCore) ERROR [core.py:1348] File ".../vllm/v1/worker/gpu_model_runner.py", line 1745, in _init_xdrope_positions
(EngineCore) ERROR [core.py:1348] assert req_state.prompt_token_ids is not None, (
(EngineCore) ERROR [core.py:1348] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
(EngineCore) ERROR [core.py:1348] AssertionError: XD-RoPE requires prompt_token_ids to be available.
(APIServer) ERROR [async_llm.py:744] vllm.v1.engine.exceptions.EngineDeadError: EngineCore encountered an issue...
(APIServer) INFO [async_llm.py] ... Application shutdown complete
(APIServer) INFO [api_server.py] Finished server process
Immediately after the request: GET /health fails — the whole server process is dead. Control group on the same server: a normal request with prompt token ids completes and the server stays alive.
rope_scaling.type == "xdrope"), (b) enables --enable-prompt-embeds, and (c) uses the V1 model runner (common supported configurations listed in Details). The attack needs no authentication when the API is exposed without --api-key and also works on unauthenticated inference aliases (e.g. /invocations); with --api-key, any authorized API caller can trigger it.Mirror commit 470229c37 in _init_xdrope_positions — replace the assertion with embeddings-aware handling:
if req_state.prompt_token_ids is not None:
input_tokens = req_state.prompt_token_ids
elif req_state.prompt_embeds is not None:
seq_len = req_state.prompt_embeds.shape[0]
input_tokens = list(range(seq_len))
else:
raise ValueError("XD-RoPE requires either prompt_token_ids or prompt_embeds.")
and add a regression test equivalent to tests/v1/worker/test_mrope_prompt_embeds.py for the XD-RoPE path (optionally, raise ValueError instead of asserting so the request fails cleanly without killing the engine).
vllm (PyPI).>= 0.28.0, < 0.30.0.0.30.0.The range covers the verified affected release and subsequent releases before the fix; earlier releases were not comprehensively assessed. PR #56078 removed the separate XD-RoPE path by unifying it with M-RoPE.
Advisory fixed in #56078.