vllm: SSRF via X-Request-Id header drives P2pNcclConnector outbound ZMQ+NCCL pair, leaking KV-cache tensors
What fixes it
- 0.24.0vllm, pipGitHub
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 usingP2pNcclConnector. - 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