Look, Don't Load Was Never a Safe Default
Picking a model in Unsloth Studio ran arbitrary Python from its config file. No weights loaded. No inference. No user approval. "The code ran from nothing more than a metadata check."
On September 29, Pillar Security's Ariel Fogel published a technical writeup of a vulnerability in Unsloth Studio — the browser UI and backend that ships inside the standard pip install unsloth package, used by a large slice of the open-source LLM fine-tuning community. The headline, in Fogel's words: "The code ran from nothing more than a metadata check."
The attack surface wasn't the training loop. It wasn't inference. It wasn't even loading a model. It was selecting one in the picker.
What the model picker actually did
Pillar's writeup, Dark Reading's coverage, and InfoWorld's all converge on the same chain. When a user selected a Hugging Face model in the Studio UI, the backend hit two endpoints — GET /api/models/config/{model_name:path} and GET /api/models/check-vision/{model_name:path} — which both called a function named load_model_config(). That function in turn called Hugging Face's AutoConfig.from_pretrained() with trust_remote_code=True hardcoded and never overridden.
trust_remote_code=True is Hugging Face's switch that lets a model repository ship its own Python modules. Some legitimate models — IBM Granite, DeepSeek-OCR — need it. The transformers library documents clearly that the setting is unsafe for untrusted repos; the whole point of the knob is that the caller is supposed to decide, per model, whether to trust it.
Unsloth Studio decided once, at the backend, and said yes to everything.
The exploit path from there is small enough to fit in a tweet. A model's config.json is allowed to declare an auto_map field pointing at Python modules in the same repository. When transformers reads the config with trust_remote_code=True, it imports and executes those modules. The config is read before weights load. Before inference. Before anything the user would recognize as "using the model." Selecting the model in the picker was enough.
Pillar's named asset list is standard for an RCE on a developer workstation: Hugging Face tokens, cloud credentials, SSH keys, proprietary datasets, model artifacts, training outputs.
The companion CVE: the problem wasn't just the UI
While Pillar was disclosing the Studio-UI route, a separate advisory landed for an overlapping primitive one layer deeper. CVE-2026-93348 (CVSS 8.6, CWE-94), disclosed September 28, covers an exec() primitive in unsloth-zoo's get_transformers_model_type() function: a nested model_type string in the model config "can turn into Python that Unsloth execs."
Affected ranges: unsloth-zoo 2025.9.9–2026.8.13 and unsloth 2025.9.9–2026.8.19. Fixed in unsloth-zoo ≥ 2026.8.14 and unsloth ≥ 2026.8.20. Dark Reading and GBHackers covered this strand too.
Two sets of version boundaries, two independent config-driven code-exec primitives in the same stack. Pipelines calling unsloth-zoo directly — not through Studio — were vulnerable along the second path.
The precedent, and why it matters outside Unsloth
Three things are worth pulling out of this disclosure, each of which generalizes well past one package.
One: the model config is a code-bearing artifact, not metadata. Every scanner, every provenance tool, every signature check that treats config.json as declarative misses what auto_map and nested model_type actually are: pointers to code that runs on read. The ecosystem's shared mental model — "weights are the dangerous part, everything else is just metadata" — is wrong against any stack that calls AutoConfig.from_pretrained(..., trust_remote_code=True) on inspection routes. Pillar's title names the subclass precisely: look, don't load. The look is the exploit.
Two: the delivery vector is the model's own declared configuration. A malicious repository doesn't need to add a file, doesn't need to typosquat, doesn't need to compromise a build. The attack lives in the file that passes every signature, SHA, and license check because it is the model's declared configuration. Repo-level provenance scanning does not raise it.
Three: "beta" was not an isolation boundary. Per InfoWorld and Dark Reading, Unsloth's maintainers initially declined to publish a security advisory or request a CVE for the Studio-specific issue, citing Studio's beta status. Pillar's response, per the same reporting: the vulnerable code shipped in the standard PyPI package — pip install unsloth — not behind a flag, not in a separate preview channel. The code was reachable without opting into beta. "Beta" was a label on the roadmap, not a boundary at runtime.
That last point is the one most portable to the rest of the AI tooling stack. Every pre-GA AI runtime in the enterprise is a shipped runtime. Every "we don't recommend production use" disclaimer is a legal position, not a filesystem permission. A beta flag that the import mechanism doesn't enforce isn't enforcing anything.
The timeline, and what to actually do
Private report reached Unsloth in early June 2026. Studio was patched in unsloth 2026.6.9 on June 18, 2026: Studio no longer loads arbitrary models directly from Hugging Face, and it no longer trusts remote code from local model files. The unsloth-zoo CVE patch landed over the following weeks. Public disclosure of the Studio chain: September 29, 2026.
If you run Unsloth: upgrade both packages — pip install -U "unsloth-zoo>=2026.8.14" "unsloth>=2026.8.20". If you can't upgrade immediately, don't select Hugging Face models in Studio.
If you run anything else that calls AutoConfig.from_pretrained() on inspection or metadata routes: audit for trust_remote_code=True. The default for that argument in transformers is False for exactly this reason. If your code sets it to True on a path that merely reads config — a picker, a validator, a search index, a model browser — treat that path as a code-execution surface for whoever controls the repo.
Look, don't load was never a safe default.
SPR{K3 is a security research operation that pairs offensive vulnerability research with runtime behavioral defense. Defend is our runtime agent. To talk about a deployment, reach us at support@sprk3.com.