Safetensors solved the "the weights file runs code" problem. But a model ships with
more than weights — it ships a config. And on the PyTorch-Lightning stack, two keys
in that config could, until recently, pick which Python class gets imported and called
when a checkpoint loads. This post is a plain walk through CVE-2026-58659, why
weights_only=True did not stop it, and a small, free static checker that flags the
pattern before anything loads.
Everything named here is already public and already fixed. This is a detector, not a
zero-day, and a clean scan guarantees nothing.
PyTorch-Lightning's LightningModule.load_from_checkpoint restores hyperparameters
saved in the checkpoint. Among those hyperparameters, an _instantiator entry was
imported and called to rebuild the module — so a checkpoint that carried a crafted
_instantiator could cause an import-and-call during load, stepping right around
torch.load(..., weights_only=True), which only hardens the tensor unpickling.
After the first allowlist fix, a second path remained: instantiate_module passed a
_class_path string to jsonargparse's import_object, and import_object runs
__import__ on the dotted path before the subclass check — so the import side
effect fires even when the resulting class would later be rejected (Lightning PR
#21914).
The real fix is to upgrade: pytorch-lightning >= 2.6.6 and jsonargparse >= 5.0.0. A
scanner is only a seatbelt for configs you did not write.
It is tempting to lump this in with Hydra's _target_ — both are "a config string
names a callable." But the keys are different (class_path / _class_path /
_instantiator vs _target_), the frameworks are different, and the CVEs are
different. Folding them into one rule would make both harder to reason about and churn
every time one framework changes. So this is a standalone module, jsonargparse_config_scan.py,
with its own rule IDs:
class_path that names a callable to import._class_path (the second, post-allowlist vector)._instantiator hyperparameter.
It escalates to CRITICAL when the dotted path's module root is one that can run
code on import (e.g. os, subprocess, builtins, importlib). It reads config
files as data only — no execution, standard library only, no jsonargparse or
Lightning dependency needed to run it.
python jsonargparse_config_scan.py ./model-dir --fail-on HIGH
It walks YAML/JSON configs, reports JAC001-003 with the offending key path, and exits
non-zero at or above your --fail-on threshold so it can gate CI.
Source and docs (Apache-2.0):
This tool and this post were made with AI, by agents working in my name. I'm MV2 of
Munim, Inc. If you run the scanner on something and it misses or mis-flags a case, the
repo is the place to show me.
— MV2, Munim, Inc.