vLLM Malicious Model Weights Deserialization RCE
An attacker embeds a hidden pickle payload inside a model checkpoint file hosted on a model hub. When a vLLM inference server loads that checkpoint, the payload runs automatically inside the server process, giving the attacker code execution on the host.
How the attack works
A malicious model file is prepared with a pickle __reduce__ trick, disguised as normal model weights. A victim's vLLM/PyTorch pipeline pulls the checkpoint and calls torch.load (with weights_only=False) or the vLLM weight iterator to deserialize it. Unpickling silently executes the embedded payload as part of loading, inside the same process that runs inference. The payload typically launches a shell, a file downloader, or an inline Python/interpreter one-liner to gain further access. The detection confirms this by tracing the exact process spawned from the model-loading step, following its real parent-child chain, and checking that the surrounding activity (checkpoint read, remote fetch, outbound connection) happened within the same short window and same process lineage — not just anywhere on the machine.
Netzilo detection
Netzilo reports this behaviour when it is observed.
- Signature ID
- 7c1e9a34-5f2b-4d68-9a01-3e6b8f2c4d17
- Severity
- High
Why it matters
An attacker can gain arbitrary code execution inside an AI inference server simply by getting it to load a poisoned model checkpoint — no direct network exploit needed. From there they can steal data, pivot into the host or cluster, or use the server as a foothold, since inference servers often run with access to GPUs, internal networks, or cloud credentials.
What you can do
- →Only load model weights from sources you trust and control; verify checksums or signatures before deployment.
- →Load checkpoints with torch.load(weights_only=True) or use safetensors format instead of pickle-based weight files wherever possible.
- →Run inference servers with least-privilege service accounts and restrict outbound network access from the process, so a payload can't easily download further tools.
- →Review startup scripts and entrypoints that fetch weights at runtime, and avoid piping downloaded content directly into a shell or writing it to writable temp directories.
Known benign look-alikes
- Container or Kubernetes entrypoints that wrap vLLM startup in "sh -c" and use curl/wget to stage weights from an internal registry before serving. These only reach the payload signature if the download is piped into a shell or written to /tmp, /var/tmp or /dev/shm and chmod +x'd.
- Distributed launchers (torchrun, Ray worker bootstrap, DeepSpeed) that spawn "python -c" one-liners importing socket or subprocess for rendezvous. This is the highest-noise benign case and is why the rule only reports.
- Interactive debugging in a Jupyter/IPython kernel that is itself a descendant of the vLLM process, where an engineer runs base64 or curl from the same lineage.
- CUDA kernel JIT compilation via torch.utils.cpp_extension (ninja, nvcc, gcc). These spawn shells but never match the payload signatures.