Three high-severity Hugging Face Diffusers vulnerabilities let a malicious model repository execute arbitrary code on any machine that loads it, no matter how carefully you set trust_remote_code=False. The flaws, tracked as CVE-2026-44827, CVE-2026-45804, and CVE-2026-44513, were patched in Diffusers 0.38.0 in early May 2026, but the full disclosure landed only on August 3, 2026. If your team pulls diffusion models from the Hugging Face Hub without pinning to 0.38.0 or later, a poisoned repo can pop a shell on your inference box with a single from_pretrained call.
The worst of the three flaws scores CVSS 8.8 and needs zero authentication from the attacker.
What exactly do the Diffusers flaws allow?
The Diffusers library is Hugging Face's toolkit for running pretrained diffusion models: image generators, video models, and similar. When you call DiffusionPipeline.from_pretrained("some-repo"), the library downloads config files, weights, and optionally custom pipeline code from the Hugging Face Hub. The trust_remote_code flag was supposed to be the gatekeeper. Set it to False, or omit it (the default), and no unreviewed Python from the repo should execute. That promise is now broken.
The Hacker News reported that three CVEs collectively defeat this gate. CVE-2026-44827 carries a CVSS score of 8.8 and is a direct code injection flaw. CVE-2026-45804 scores 7.5 and is a race condition. CVE-2026-44513 also scores 8.8 and covers three related variants sharing the same root cause.
Security firm Zafran, which discovered and reported the vulnerabilities, published a full technical writeup branding the collection "FaceHugger." Every variant traces to one root cause: a classic Time-of-Check to Time-of-Use (TOCTOU) flaw. A model download that should be a single atomic operation was split into two sequential, non-atomic HTTP requests, and the security gate that enforces trust_remote_code runs only against the first. The second request can pull entirely different content.
The practical impact is severe. An attacker publishes a model repository on the Hugging Face Hub that looks legitimate. When a victim runs from_pretrained on that repo, arbitrary Python executes on the victim's machine. The attacker needs no credentials, no network position, and no user interaction beyond the victim loading a model they already intended to load.
How does the None.py trick bypass trust_remote_code?
CVE-2026-44827 is the most elegant of the three. The NVD entry describes the mechanism precisely. The _resolve_custom_pipeline_and_cls function in pipeline_loading_utils.py performs string interpolation on the custom_pipeline parameter using f"{custom_pipeline}.py". When custom_pipeline is not supplied by the user, it defaults to None, which Python interpolates as the literal string "None.py".
If an attacker publishes a Hub repository containing a file named None.py with a class that subclasses DiffusionPipeline, that file gets automatically downloaded and executed during a standard DiffusionPipeline.from_pretrained() call with no additional keyword arguments. The trust_remote_code check in DiffusionPipeline.download() is bypassed because it evaluates custom_pipeline is not None as False since the kwarg was never supplied, while the downstream code path resolves the None value into "None.py" and loads it.
This is the part that should make any platform engineer uncomfortable. The guard rail does not fail open or fail closed. It fails to evaluate at all, because the code path that loads the file is decoupled from the code path that checks the flag. A file named None.py in a model repo is all it takes to turn a data pull into remote code execution.
The GitHub advisory for the related TOCTOU variant, GHSA-7wx4-6vff-v64p, confirms that the from_pretrained call succeeds and returns a functional pipeline, so the victim sees nothing unusual. The model loads. The pipeline runs. The attacker's code already executed.
How wide is the TOCTOU race window?
CVE-2026-45804 is the race condition variant, and it is the one that scales to repositories you already trust. The NVD record confirms the vulnerability allows arbitrary code introduction between the two download calls. The download process makes two sequential HTTP calls to the Hub: first hf_hub_download, then snapshot_download. The trust check operates on the content fetched by the first call, which resolves to commit A. The second call can silently fetch a newer commit B where the config has been modified to point to custom code. If the config was modified to point to custom code between the two calls, it will be executed.
Zafran's local testing showed the attacker has roughly a 0.3-second window to push changes between the two requests. That is tight but feasible for an attacker who controls the repository and can time the victim's pull, or who can observe download patterns to predict when the window opens.
The attack flow works as follows. The victim calls from_pretrained on a repository. hf_hub_download fetches model_index.json at commit A, which is clean. The trust check passes because no custom pipeline code is detected. The attacker then pushes commit B, adding a None.py or a modified config that references custom code. snapshot_download fetches the full repository at commit B, which now contains the malicious payload. The downstream code resolves and executes the injected code.
For a repository you do not control, the attacker would need to compromise the repository owner's account or inject a commit through some other means. For a repository the attacker publishes themselves, which is the None.py scenario, there is no race to win. The poisoned file is there from the start.

The chart above shows the CVSS scores for all three CVEs. CVE-2026-44827 and CVE-2026-44513 both land at 8.8, while the race condition variant CVE-2026-45804 scores 7.5. All three were patched in the same release.
What does this mean for your model loading pipeline?
If you run any Diffusers version before 0.38.0, you are exposed. The fix shipped in Diffusers 0.38.0, released in early May 2026. Any environment that has not updated is running vulnerable code.
The threat model here is broader than "I pulled a sketchy model from the Hub." Consider the scenarios that should worry you:
- A team member finds a model on the Hub for a prototype and runs
from_pretrainedwithout checking the repository contents. This is the default workflow Diffusers is designed for, and it is now an attack vector. - A CI pipeline downloads models for testing or benchmarking. If the model repository is compromised between builds, the race condition variant applies. Your CI runner now executes attacker code with whatever permissions the pipeline carries.
- A fine-tuning pipeline pulls a base model from the Hub. The base model repository is maintained by a third party you do not control. If their account is compromised, your training environment is compromised.
- A notebook environment on a shared GPU server loads models from the Hub. The attacker gets code execution on that server, which may have access to other users' data or shared credentials.
The Hugging Face autonomous agent breach we covered earlier this year showed that the Hub's ecosystem is already in the crosshairs. These Diffusers vulnerabilities make the attack surface materially worse because they remove the need for the attacker to trick a user into setting trust_remote_code=True. The default, safe-looking path is the vulnerable one.
For builders running inference infrastructure, the stakes are concrete. A malicious model repository gives the attacker code execution in the context of whatever process loads the model. If that process runs in a container with cloud credentials mounted, the attacker now has your cloud credentials. If it runs on a GPU node in a cluster, the attacker has a foothold in your training or inference fleet. The blast radius depends entirely on how you isolate model loading, and most teams do not isolate it meaningfully.
Every model pull from an external repository is a supply chain event. Treat it like one.
What should you do right now to lock down Diffusers?
The fix is straightforward. The operational hardening is not. Here is the playbook.
Patch immediately. Upgrade to Diffusers 0.38.0 or later in every environment that loads models from the Hub. Check your requirements files, Docker images, and notebook environments. Diffusers is often installed as a transitive dependency, so search for it in your lockfiles, not just your direct dependencies.
pip install diffusers>=0.38.0
Pin your model repositories. Instead of pulling from a repository by name, pin to a specific commit hash. This defeats the race condition variant because both HTTP calls resolve to the same immutable commit.
DiffusionPipeline.from_pretrained(
"org/model-name",
revision="a1b2c3d4e5f6" # specific commit hash
)
Sandbox model loading. Run from_pretrained in a container with no cloud credentials, no network egress beyond the Hub, and no persistent filesystem. Copy the loaded model artifacts out to object storage, then load from local files in your inference environment. This is the defense that survives the next vulnerability in this class.
Audit your Hub pulls. Search your codebase for from_pretrained and DiffusionPipeline. Every call site is a potential entry point. For each one, verify that the repository is owned by a trusted organization and that you are pinning to a specific revision.
Watch for follow-on CVEs. The TOCTOU pattern in these flaws is not unique to Diffusers. Any library that downloads executable code in multiple HTTP requests without atomic verification has the same structural weakness. Expect similar findings in other model-loading ecosystems.
The supply chain lesson
The trust_remote_code flag was a promise: if you do not opt in, unreviewed code will not run. These CVEs show that a flag is only as good as the code path that enforces it. When the check and the load are decoupled, the attacker gets to choose which one applies. The fix is not a better flag. It is a download protocol where trust verification and content delivery are a single atomic operation, or where untrusted code never executes in the first place. Until the Hub and its client libraries get there, your container boundary is the only gate that matters.
