All vulnerabilities
GHSA-vfp2-c8pq-v6h6

vllm: SSRF via X-Request-Id header drives P2pNcclConnector outbound ZMQ+NCCL pair, leaking KV-cache tensors

vllm
CVSS
n/aHigh
ExploitationNo known exploitationNot in CISA KEV, which does not prove it is unexploitedCISA KEV
Exploit odds (EPSS)No scoreNo FIRST EPSS score in this snapshot yet
Fixed in0.24.0Fixed versionGitHub
Published9 Oct 2026Updated 9 Oct 2026GitHub

What fixes it

A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.

Description

Summary

OpenAIServing._base_request_id copies the HTTP X-Request-Id header verbatim into the request_id used throughout the vLLM engine, and P2pNcclConnector.parse_request_id extracts an arbitrary host:port from that value via a permissive regex with no allow-list or scheme check. An API caller can embed a routing token in X-Request-Id to force a prefill worker running with P2pNcclConnector to ZMQ-DEALER-connect outbound to an attacker-controlled host, share the NCCL communicator unique_id over that channel, and ultimately ncclSend the KV-cache tensors of the targeted request to the attacker. The affected V1 connector is present in vLLM >= 0.9.2, < 0.24.0.

Details

vllm/entrypoints/openai/engine/serving.py:399 (OpenAIServing._base_request_id) returns raw_request.headers.get("X-Request-Id") verbatim, so the user-controlled header value becomes the base request_id for any /v1/completions or /v1/chat/completions request. vllm/distributed/kv_transfer/kv_connector/v1/p2p/p2p_nccl_connector.py:450 (parse_request_id) then applies the regex r"___decode_addr_(.*):(\d+)" with no allow-list, scheme check, or IP-literal block to extract ip and port.

vllm/distributed/kv_transfer/kv_connector/v1/p2p/p2p_nccl_engine.py:207 (create_connect) calls sock.connect(f"tcp://{remote_address}") and immediately sends msgpack.dumps({"cmd": "NEW", "unique_id": bytes(unique_id.internal)}) before calling ncclCommInitRank, and at line 533 send_sync dispatches the KV cache via ncclSend over that communicator — both steps execute against whatever host the attacker named.

Requires --kv-transfer-config '{"kv_connector":"P2pNcclConnector","kv_role":"kv_producer",...}'; no additional privileges beyond a valid API key (or no key if --api-key is unset).

Affected versions and remediation

  • Package: vllm (PyPI).
  • Affected versions: >= 0.9.2, < 0.24.0, when using P2pNcclConnector.
  • Patched version: 0.24.0.
  • PR #44854 removed the affected connector and its registration.

Impact

Any API client that can reach a prefill worker running P2pNcclConnector can exfiltrate the full KV-cache (prompt text and prefix-cached hidden states) of any request that worker processes, using only an HTTP header. The leak also includes the NCCL communicator unique_id, and the blocking ncclCommInitRank call against an unresponsive attacker host constitutes a denial-of-service vector against the prefill worker. CWE-918 (Server-Side Request Forgery), severity high.

Fix

OpenAIServing._base_request_id in vllm/entrypoints/openai/engine/serving.py must strip or replace X-Request-Id with a random UUID when P2pNcclConnector is active, preventing any user-supplied value from reaching parse_request_id. Additionally, create_connect in vllm/distributed/kv_transfer/kv_connector/v1/p2p/p2p_nccl_engine.py must validate remote_address against an operator-configured CIDR/hostname allow-list (supplied via kv_connector_extra_config) before opening the ZMQ socket and initiating NCCL bootstrap.

Text from GitHub Advisory Database

Affected versions 1

  • vllm, pip>= 0.9.2, < 0.24.0GitHub