Blog
5
min read
Trust Disabled, Code Executed: Arbitrary Code Execution in Unsloth’s Model Loader
.webp)
Executive summary
What happened. Pillar Security discovered an arbitrary-code-execution vulnerability in Unsloth’s core model-loading path. An attacker-controlled model configuration could cause Python code to execute during loading. The vulnerability is tracked as CVE-2026-93348, rated High, with a CVSS v4.0 score of 8.6.
Why it matters. The affected code ran inside the model-loading process, with access to whatever that process could read, modify, or authenticate to. In an AI development environment, that can include proprietary datasets, model artifacts, Hugging Face tokens, and cloud credentials. Exploitation required an affected loading path to process an attacker-controlled configuration.
How it worked. Unsloth used configuration-derived model_type values to locate the model implementation it wanted to optimize. Insufficiently validated values reached a generated Python import statement executed through exec(). This translated to a command injection vulnerability, leveraging configuration data.
What changed. The maintainers merged the initial fix approximately six hours after our private report. It first shipped in unsloth_zoo 2026.8.14. Enterprise clients rely on CVE registries to identify and patch supply chain risks. Unfortunately, the maintainers never acknowledged the initial report or responded to subsequent follow-ups. This meant we discovered the vulnerability was patched by chance and needed to publish using a third-party CVE Numbering Authority to ensure that users were adequately informed. VulnCheck published the CVE on September 28, 2026.
Enterprise relevance. Unsloth is part of established AI development workflows: Databricks includes the library in its AI v5 environment. Unsloth’s reach extends beyond fine-tuning software into the model supply chain. Hugging Face identifies it as the third-largest source of model derivatives on the Hub, after Qwen and Google. As a Forbes analysis highlights, enterprises need visibility into the third-party model artifacts entering their workflows and the organizations supplying them.
What users should do. Check the packages actually installed in notebooks, training workers, and container images. The reported issue was first fixed in unsloth_zoo 2026.8.14; unsloth 2026.8.20 was the first release whose dependency floor excluded vulnerable Zoo versions.
How a model name became executable code
In “Look, Don’t Load,” we described how a beta-release version of Unsloth Studio executed repository-provided Python during model inspection. This vulnerability, discovered in the generally available unsloth library and utilities, exploited a different model loading behavior, this time focusing on how unsloth leverages certain fields in its model configuration during the process.
Unsloth uses a model’s model_type to find the matching implementation it wants to optimize. For example, a configuration containing "model_type": "llama" should lead it to import the Llama implementation from Transformers:
Once imported, Unsloth can inspect the module’s source and apply its model-architecture specific optimizations. To support the different architectures, the compiler constructed an import statement dynamically:
With an ordinary value such as llama, this produces the expected import. But model_type came from the model’s configuration, which an attacker could control. The configuration reader, get_transformers_model_type(), collected these values from nested objects as well as the top-level configuration, then normalized them, and performed model-name compatibility checks without strictly restricting every result to a safe identifier.
That matters because exec() executes the entire constructed string as Python code. We realized that we could craft a nested model_type that includes a newline, then introduces additional Python statements into the generated import. Those statements would then get executed at the exec() line, before the subsequent eval() lookup. Like the previous unsloth vulnerability we found, setting trust_remote_code=False would not prevent this code execution, as Unsloth’s own loader turned configuration data into code without using the custom remote-code mechanism.
Demonstration and impact
In our testing, loading the crafted model configuration triggered code execution before weights or the tokenizer were loaded, while still allowing the model load to complete successfully.
The injected code inherited the loading process’s permissions. On a training worker or developer notebook, that could expose proprietary datasets, model artifacts, Hugging Face tokens, cloud credentials, or allow an attacker to alter training outputs and access other systems using the job’s credentials.
A fast fix, followed by a disclosure gap
We reported the vulnerability privately on August 22, 2026. The maintainers merged the initial fix approximately six hours later and a patched unsloth-zoo package shipped late on August 24.
The initial patch added identifier validation and replaced the generated import and subsequent eval() lookup with:
This preserved the intended module selection without interpreting its name as Python source. Subsequent hardening added validation at the compiler entry point itself.
While the technical response was quick, our attempts to communicate with unsloth maintainers to coordinate on disclosure were unsuccessful. Though we sent direct messages to the maintainers linking to the private github advisory, followed by messages on August 24, August 27, and September 7, they didn’t reply to acknowledge the vulnerability or coordinate on next steps.
On September 20, we discovered that the maintainers had already released a fix. We contacted them directly again to establish next steps for coordinating disclosure. After receiving no response to that outreach, we approached VulnCheck later the same day, which quickly responded and published CVE-2026-93348 on September 28.
Disclosure timeline
A fix needs to reach the people at risk
The maintainers fixed the vulnerability quickly, but affected packages continued to circulate. From August 25 through September 27 (the reporting window ending the day before CVE publication), vulnerable unsloth-zoo releases recorded 84,582 download events.
Enterprise environments are part of the distribution picture. During our review, Databricks’ AI environment v5 documentation still listed unsloth 2025.11.3 and unsloth_zoo 2026.1.2, both within the published affected ranges (archived version here). Users could receive affected dependencies through a managed environment without installing Unsloth themselves.
These observations explain why patching and disclosure belong together. A patch makes a corrected version available. An advisory tells users and downstream maintainers why they need it, which environments to inspect, and which versions close the issue.
That information helps turn an upstream fix into rebuilt images, updated runtimes, and patched notebooks. Without a clear security notice, an update can look like routine maintenance while affected code continues to reach users.
What to update
The vulnerable implementation was in unsloth-zoo. Unsloth exposed users to it through the loading workflow and dependency requirements.
An older Unsloth release can be paired with a patched Zoo dependency, so the installed package set matters. The dependency update excluded vulnerable Zoo versions from a dependency-respecting installation.
Platform and security teams should:
- Inspect the running environment: Check both packages in notebook kernels, training workers, and deployed containers.
- Update the artifacts that preserve dependencies: Refresh lockfiles, rebuild images, and restart processes using older packages.
- Verify managed runtimes: Confirm installed versions or obtain a software inventory from the provider.
- Restrict model-loading access: Limit credentials, mounted data, and network permissions to what each workload requires.
FAQs
Am I affected by CVE-2026-93348?
If your environment has unsloth-zoo between 2025.9.9 and 2026.8.13, or unsloth between 2025.9.9 and 2026.8.19, yes. The vulnerable code lived in unsloth-zoo, and unsloth pulled it in as a dependency. Check both packages in notebook kernels, training workers, and container images, including managed runtimes such as Databricks environments.
Which versions fix the vulnerability?
unsloth_zoo 2026.8.14 was the first release with the fix. unsloth 2026.8.20 was the first release whose dependency floor excluded vulnerable Zoo versions. An older unsloth release paired with a patched Zoo is also protected, so the installed package set is what matters.
Does setting trust_remote_code=False protect me?
No. The vulnerable path did not use the Hugging Face remote-code mechanism. Unsloth's own loader built a Python import statement from the model_type value in the model configuration and ran it through exec(), so the trust_remote_code setting had no effect.
Why did a third party publish the CVE?
The maintainers merged a fix within hours of our private report but did not respond to that report or to follow-ups on August 24, August 27, September 7, and September 20. To make sure users and downstream platforms were informed, we worked with VulnCheck, a CVE Numbering Authority, which published CVE-2026-93348 on September 28, 2026.
Subscribe and get the latest security updates
Back to blog
.webp)
%20(1).webp)
%20(1).webp)


.webp)







