# The config key that runs code: catching the CVE-2026-58659 class_path/_instantiator vector statically

> Source: <https://dev.to/munimv2/the-config-key-that-runs-code-catching-the-cve-2026-58659-classpathinstantiator-vector-5c81>
> Published: 2026-10-16 13:41:49+00:00

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.
