PyTorch: `torch.load` with `weights_only=True` leads to remote code execution
Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.
Affected versions
Details
# Description I found a Remote Command Execution (RCE) vulnerability in PyTorch. When loading model using torch.load with weights_only=True, it can still achieve RCE. # Background knowledge https://github.com/pytorch/pytorch/security As you can see, the PyTorch official documentation considers using `torch.load()` with `weights_only=True` to be safe.  Since everyone knows that weights_only=False is unsafe, so they will use the weights_only=True to mitigate the seucirty issue. But now, I just proved that even if you use weights_only=True, it can still achieve RCE. # Credit This vulnerability was found by Ji'an Zhou.
The fix
Prevent legacy_load when weights_only=True (correctly)
test/test_serialization.py+5 −1
@@ -462,7 +462,11 @@ def _test_serialization_backwards_compat(self, weights_only):b += [a[0].storage()]b += [a[0].reshape(-1)[1:4].clone().storage()]path = download_file('https://download.pytorch.org/test_data/legacy_serialized.pt')-c = torch.load(path, weights_only=weights_only)+if weights_only:+with self.assertRaisesRegex(RuntimeError,+"Cannot use ``weights_only=True`` with files saved in the legacy .tar format."):+c = torch.load(path, weights_only=weights_only)+c = torch.load(path, weights_only=False)self.assertEqual(b, c, atol=0, rtol=0)self.assertTrue(isinstance(c[0], torch.FloatTensor))self.assertTrue(isinstance(c[1], torch.FloatTensor))
torch/serialization.py+12 −6
@@ -85,6 +85,13 @@IS_WINDOWS = sys.platform == "win32"+UNSAFE_MESSAGE = (+"In PyTorch 2.6, we changed the default value of the `weights_only` argument in `torch.load` "+"from `False` to `True`. Re-running `torch.load` with `weights_only` set to `False` will likely succeed, "+"but it can result in arbitrary code execution. Do it only if you got the file from a "+"trusted source."+)+if not IS_WINDOWS:from mmap import MAP_PRIVATE, MAP_SHAREDelse:@@ -1324,12 +1331,6 @@ def load(>>> torch.load("module.pt", encoding="ascii", weights_only=False)"""torch._C._log_api_usage_once("torch.load")-UNSAFE_MESSAGE = (-"In PyTorch 2.6, we changed the default value of the `weights_only` argument in `torch.load` "-"from `False` to `True`. Re-running `torch.load` with `weights_only` set to `False` will likely succeed, "-"but it can result in arbitrary code execution. Do it only if you got the file from a "-"trusted source."-)DOCS_MESSAGE = ("\n\nCheck the documentation of torch.load to learn more about types accepted by default with ""weights_only https://pytorch.org/docs/stable/generated/torch.load.html."@@ -1592,6 +1593,11 @@ def persistent_load(saved_id):with closing(tarfile.open(fileobj=f, mode="r:", format=tarfile.PAX_FORMAT)) as tar, mkdtemp() as tmpdir:+if pickle_module is _weights_only_unpickler:+raise RuntimeError(+"Cannot use ``weights_only=True`` with files saved in the "+"legacy .tar format. " + UNSAFE_MESSAGE+)tar.extract("storages", path=tmpdir)with open(os.path.join(tmpdir, "storages"), "rb", 0) as f:num_storages = pickle_module.load(f, **pickle_load_args)
References
- WEBhttps://github.com/pytorch/pytorch/security/advisories/GHSA-53q9-r3pm-6pq6
- ADVISORYhttps://nvd.nist.gov/vuln/detail/CVE-2025-32434
- WEBhttps://github.com/pytorch/pytorch/commit/8d4b8a920a2172523deb95bf20e8e52d50649c04
- WEBhttps://github.com/pypa/advisory-database/tree/main/vulns/torch/PYSEC-2025-41.yaml
- PACKAGEhttps://github.com/pytorch/pytorch