High

vLLM PyNcclPipe Unsafe Pickle Deserialization RCE

vLLM's disaggregated-prefill feature moves data between servers using Python's pickle format, which can execute arbitrary code when loading untrusted input. An attacker who can reach this channel can trigger remote code execution on the vLLM server, and a related networking bug means the channel is often reachable even when configured to be private.

How the attack works

vLLM's PyNcclPipe/PyNcclConnector KV-transfer channel receives data over a socket and deserializes it with pickle.loads(). Pickle deserialization can be abused with a crafted object implementing __reduce__ to execute arbitrary code the moment it's loaded, so any attacker who can send bytes to this channel gets code execution as the vLLM process. Separately, PyTorch's TCPStore component binds to all network interfaces (0.0.0.0) even if the deployment was configured with a private kv_ip, so a supposedly internal KV-transfer endpoint can still be exposed to the network. The rule flags command lines or tool calls that combine a vLLM KV-transfer indicator with either a known deserialization/RCE primitive (pickle.loads/dumps, __reduce__, send_obj/recv_obj, etc.) or an all-interfaces listener configuration (kv_ip=0.0.0.0, kv_port=18888, TCPStore master).

Netzilo detection

Netzilo reports this behaviour when it is observed.

Signature ID
3f7a1c92-5e84-4d6b-9a1f-0c2be7d5a483
Severity
High

Why it matters

An attacker able to reach the KV-transfer socket can run arbitrary code with the privileges of the vLLM server, potentially leading to full compromise of the inference host and anything it can access.

What you can do

  • Do not expose the KV-transfer channel (PyNcclPipe/PyNcclConnector) to untrusted networks; bind it to a private interface and restrict access with firewall rules regardless of the configured kv_ip, since TCPStore may still listen on 0.0.0.0.
  • Audit any deployment using --kv-transfer-config for kv_ip 0.0.0.0 or kv_port 18888 and treat it as an exposure needing remediation even without evidence of exploitation.
  • Run vLLM disaggregated-prefill workers in network-isolated segments (e.g., a dedicated VLAN or namespace) reachable only by trusted peer nodes.
  • Upgrade vLLM to a version that patches this deserialization issue once available, and monitor vendor advisories for the CVE.

Known benign look-alikes

  • Legitimate vLLM disaggregated-prefill deployment launched with --kv-transfer-config containing kv_ip 0.0.0.0 or kv_port 18888. This is a true exposure of the vulnerable service, not exploitation; triage as configuration risk rather than intrusion.
  • vLLM upstream KV-transfer test suite exercising StatelessProcessGroup.send_obj/recv_obj. Suppressed by filter_tests (pytest/unittest markers).
  • Security engineers reading or writing an advisory, PoC write-up or changelog entry for this CVE. Suppressed by filter_docs.
  • Developers patching pynccl_pipe.py to add a RestrictedUnpickler, find_class allowlist or weights_only load. Suppressed by filter_defensive.
  • Internal benchmark harnesses that pickle tensors for KV transfer as part of a measured baseline; these still warrant review because they exercise the vulnerable path.

References