cd /news/ai-safety/the-pytorch-checkpoint-container-is-… · home › topics › ai-safety › article
[ARTICLE · art-160337] src=dev.to ↗ pub= topic=ai-safety verified=true sentiment=· neutral

The PyTorch checkpoint container is itself a security signal: CVE-2025-32434 and the legacy load path

A developer at Munim, Inc. added pytorch_checkpoint_scan.py to the open-source keras-model-scan toolkit, a static, dependency-free scanner that identifies whether a PyTorch checkpoint is a modern ZIP, legacy tar, or bare pickle and disassembles the embedded pickle opcodes with pickletools without importing torch or executing anything. The tool targets CVE-2025-32434 (CVSS 9.3, affecting torch ≤ 2.5.1 and fixed in 2.6.0), in which the legacy load path failed to apply the restricted unpickler, so torch.load(weights_only=True) could still execute dangerous callables in legacy-format files. The scanner exits 1 on high-severity findings and treats the checkpoint container format as part of the threat model.

by read2 min views1 publishedOct 29, 2026

Most pickle scanners answer one question about a model file: does the pickle inside it import something dangerous? That is the right question, but it skips a quieter one that turned out to matter a great deal in 2025: which container is the pickle sitting in, and what does torch.load do with that container?

torch.load has two deserialisation paths:

torch.save writes a ZIP archive whose archive/data.pkl member is the object graph. The restricted unpickler that weights_only=True installs is wired into this path.pytorch_model.bin often takes — is handled by _legacy_load. For years the community advice was: to load an untrusted checkpoint, pass weights_only=True. That was supposed to swap in a restricted unpickler that only rebuilds tensors and refuses arbitrary callables.

CVE-2025-32434 (published 2025-04-17, CWE-502, CVSS 9.3/9.8, torch ≤ 2.5.1, fixed in 2.6.0) is the hole in that advice. On affected versions, _legacy_load did not apply the restricted unpickler. So torch.load(path, weights_only=True) — the exact call people reached for to be safe — still executed whatever callable a legacy-format file named. The modern zip path was fine; the legacy path was not. PyTorch 2.6.0 fixed the path and flipped the default to weights_only=True.

The practical takeaway: on vulnerable torch, the container format decided whether "safe mode" was actually safe. A dangerous import in a legacy file was reachable under weights_only=True; the same import in a modern-zip file needed weights_only=False. The container is a signal, not just packaging.

I added pytorch_checkpoint_scan.py to the open-source keras-model-scan toolkit. It is static and dependency-free: it never imports torch, never extracts an archive member to disk, and never unpickles or executes anything. It reads the bytes, recognises the container (zip vs tar vs bare pickle) with zipfile/ tarfile, pulls the embedded pickle(s) out, and disassembles their opcodes with the standard library's pickletools. Then it reports with the container in mind:

torch.load(weights_only=True) on torch ≤ 2.5.1.torch.load(weights_only=False).

python pytorch_checkpoint_scan.py pytorch_model.bin model.pt

Exit 1 on any high finding, 0 otherwise (PTC010 prints but does not fail the build).

This is static source review, not exploitation. It flags imports and container shape; it does not prove a given file is exploitable and it runs no proof-of-concept. It reports the first dangerous import path per member, and nuanced top-level-package gadget classification (the torch.* gadget paths some denylists catch) lives in a separate module in the same repo. The point here is narrow and, I think, underserved: treat the checkpoint container as part of the threat model, because torch.load did.

This post and the tool it describes were made with AI agents working in the name of MV2 of Munim, Inc. The work is open source under Apache-2.0. If you spot a mistake, the repo is the place to raise it.

── more in #ai-safety 4 stories · sorted by recency
── more on @pytorch 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/the-pytorch-checkpoi…] indexed:0 read:2min 2026-10-29 · —