torch.load is only as safe as the file you give it. It uses an unpickler under the hood, and PyTorch's docs say never to load data from an untrusted source. Setting weights_only=True restricts what can be loaded to tensors and simple types, which removes the main code execution path.
What torch.load actually does
A PyTorch checkpoint saved the traditional way is a pickle. Pickle is a stack of instructions, and some of those instructions can import a module and call a function while the file is being read. That is why the Python documentation warns that malicious pickle data can execute arbitrary code during unpickling.
So loading a checkpoint is not like opening an image. It is closer to running a small program written by whoever made the file.
What weights_only restricts
The current PyTorch documentation describes the weights_only argument as telling the unpickler to load only tensors, primitive types, dictionaries and any types you explicitly allow through add_safe_globals. The signature in the docs shows weights_only=True as the default.
PyTorch's security policy goes further. It says torch.load with weights_only set to true ensures no remote code execution or out-of-bounds access during the deserialization itself. It also says this does not guarantee that the deserialized objects will be usable later.
import torch
# Explicit is better than relying on a default that may differ by version
state = torch.load("checkpoint.pt", weights_only=True, map_location="cpu")
model.load_state_dict(state)
What it does not cover
Three gaps are worth knowing.
- Older environments. Your team may run several PyTorch versions across laptops, CI and training clusters. Do not assume the default is the same everywhere. Pass the argument explicitly.
- Distributed checkpoints. The PyTorch policy states that the weights_only protections of torch.load do not apply to distributed checkpoints.
- Everything around the file. A repository can also ship a training script, a notebook or custom model code. Restricting the unpickler does nothing about code you run on purpose.
The policy also says that running untrusted models is equivalent to running untrusted code, and recommends a secure, isolated environment such as a sandbox for that case.
A practical loading routine
| Situation | Suggested handling |
|---|---|
| Your own checkpoint from your own pipeline | weights_only=True, record the file hash |
| A checkpoint from a vendor you know | weights_only=True, verify the hash they publish, prefer a non-pickle format |
| A checkpoint from an unknown uploader | Do not load on a machine with credentials; use an isolated sandbox or skip it |
| A checkpoint that fails to load with weights_only=True | Treat the failure as information. Find out which type it needs before allowing anything |
When a load fails because the file contains a custom class, the tempting fix is to turn the restriction off. Resist that. Look at what the class is, and if you trust it, allow that one type with add_safe_globals instead.
Where Safeguard fits
The framework itself is a dependency, and so is every package in your training image. Safeguard can build an SBOM for your Python projects, flag known vulnerable versions, and use reachability analysis to show which findings your code actually calls. You can try a free scan at gold.safeguard.sh/scan. For the wider picture, see model hub supply chain risks.
Quick check
Does weights_only=True make any model file safe to use?
No. It restricts what the unpickler will build during loading. It does not vouch for the training code, the notebook or the custom modules that ship with a model, and it does not apply to distributed checkpoints.
Should I still prefer a non-pickle format?
Yes, where the model is available in one. Hugging Face describes safetensors as a format for storing tensors safely, as opposed to pickle.
Sources
Last reviewed: 19 October 2026.