---
id: "GHSA-5q78-j82c-2vr2"
page: "https://infrastack.ai/live/GHSA-5q78-j82c-2vr2"
kind: "vulnerability"
aliases: ["GHSA-5q78-j82c-2vr2"]
title: "vLLM denial of service via prompt embeds on XD-RoPE models (incomplete fix of CVE-2026-55514)"
severity: "medium"
cvss: 5.9
epss: null
exploited: false
status: "open"
category: "ai-tooling"
products: [{"name": "vllm", "fixed": ["0.30.0"], "affected": ">= 0.28.0, < 0.30.0", "ecosystem": "pypi"}]
ecosystems: ["pypi"]
tags: ["ai-tooling", "cwe-617", "gpu-inference", "python", "self-hosted", "vllm", "xd-rope"]
not_affected_if: ["no-xdrope-models", "prompt-embeds-disabled", "version-0.30.0-or-later"]
published_at: "2026-10-27T22:18:41+00:00"
first_seen_at: "2026-11-09T22:53:23+00:00"
updated_at: "2026-11-09T22:56:21+00:00"
sources: [{"source": "ghsa-repo", "url": "https://github.com/vllm-project/vllm/security/advisories/GHSA-5q78-j82c-2vr2", "first_seen_at": "2026-11-09T22:53:23+00:00"}]
exploit_sources: []
---

# vLLM denial of service via prompt embeds on XD-RoPE models (incomplete fix of CVE-2026-55514)

Link for people: https://infrastack.ai/live/GHSA-5q78-j82c-2vr2 (this .md is for agents)

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.

_Summary, check and fix written by a model from the sources; labelled as such._

## Affected

- pypi:vllm affected >= 0.28.0, < 0.30.0 fixed 0.30.0

## How to check

- Check the installed version with `pip show vllm` and compare against the affected range `>= 0.28.0, < 0.30.0`.
- Look for a served model whose HF config has `rope_scaling.type == "xdrope"` (for example `tencent/HunyuanOCR`).
- Check whether the server is started with `--enable-prompt-embeds`.
- Check whether the V1 model runner is in use (`VLLM_USE_V2_MODEL_RUNNER=0` or the other configurations listed in the advisory).

## Fix

- `vllm` `0.30.0` (first stable patched version; the advisory is fixed in PR #56078).

## Timeline

- 2026-11-09T22:53:23+00:00 ghsa-repo https://github.com/vllm-project/vllm/security/advisories/GHSA-5q78-j82c-2vr2

## Documents

- [advisory] Maintainer's advisory: github.com https://github.com/vllm-project/vllm/security/advisories/GHSA-5q78-j82c-2vr2

## From the sources

### Summary

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 `vllm==0.28.0` wheel on a real GPU: one attack request makes the whole server process terminate (all concurrent clients disconnected).

### Details

**Affected code** (`vllm/v1/worker/gpu_model_runner.py`, V1 GPU model runner; lines 1742–1746 in v0.28.0, 1689–1694 in `main` @ `6f7df92a8`):

```python
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`):

```python
# 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):**
1. `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.
2. `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.
3. `vllm/v1/request.py:145-146` — embeddings-only requests are first-class (`_all_token_ids` is a zero-filled placeholder list).
4. On first scheduling, `_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.

### Impact

- **Vulnerability type:** reachable assertion leading to full denial of service (CWE-617). One request kills the EngineCore and terminates the API server process; every concurrent client is disconnected and the service must be restarted.
- **Impact:** availability of the entire serving instance; for multi-tenant deployments, all tenants are affected simultaneously.
- **Who is impacted:** any deployment that (a) serves an XD-RoPE model (`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.
- **Same-class reference:** CVE-2026-55514 / GHSA-33cg-gxv8-3p8g (M-RoPE variant, rated High); this report is the incomplete-fix variant of that advisory.

### Suggested fix (for the maintainer)

Mirror commit `470229c37` in `_init_xdrope_positions` — replace the assertion with embeddings-aware handling:

```python
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).

## Affected versions

- Package: `vllm` (PyPI).
- Affected versions: `>= 0.28.0, < 0.30.0`.
- First stable patched version: `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](https://github.com/vllm-project/vllm/pull/56078).

---

_Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai_
