Threat · curated 27 Jul 2026

FaceHugger: Hugging Face Diffusers Flaws Open Door to AI Supply Chain Attacks

Dossier

Coverage timeline

27 Jul 2026zafran.io

Single-source research — first reported, latest, and curated coincide.

Why it matters

The diffusers library sees roughly 200,000 installs a day across enterprise CI/CD and production pipelines, so a bypass of trust_remote_code turns a routine model download into an initial-access vector deep inside AI supply chains.

Zafran Labs disclosed a set of high-severity vulnerabilities (CVE-2026-44827 CVSS 8.8, CVE-2026-45804 CVSS 7.5, and CVE-2026-44513 CVSS 8.8) in Hugging Face's widely used diffusers library that let a malicious model repository silently execute arbitrary code on any client that loads it. The root cause is a Time-of-Check to Time-of-Use (TOCTOU) flaw: a model download is split into two non-atomic HTTP requests, and the trust_remote_code safeguard is only enforced against the first, allowing the check to be bypassed. The write-up ties the flaw to a July 2026 Hugging Face intrusion in which a malicious dataset abused dataset-processing code-execution paths.

vuln-research

Summary

Zafran Labs, as part of its Project DarkSide research, disclosed a set of high-severity vulnerabilities in Hugging Face's diffusers library that let a malicious model repository silently execute arbitrary code on any client machine that loads it, bypassing the trust_remote_code safeguard designed to stop unreviewed custom pipeline code from running.[0]

Every variant traces to a single root cause: a Time-of-Check to Time-of-Use (TOCTOU) flaw in which a model download that should be atomic is split into two sequential, non-atomic HTTP requests, with the security gate enforcing trust_remote_code running only against the first request. The findings comprise CVE-2026-44827 (CVSS 8.8), a code-injection flaw; CVE-2026-45804 (CVSS 7.5), a race condition; and three related variants tracked under CVE-2026-44513 (CVSS 8.8), the latter reported by GitHub user Vancir.[0][2][3][4][5]

Because diffusers draws roughly 7 million downloads per month (~200,000 installs per day) and is embedded in production pipelines, CI/CD systems, and container images, a single compromised model load could hand an attacker initial access deep inside an enterprise environment. Zafran links the model-loading weakness to Hugging Face's July 2026 security incident, in which a malicious dataset abused code-execution paths to escalate to node-level access and move laterally across internal clusters.[0][1]

Attack chain

  1. None.py trust bypass (CVE-2026-44827): An attacker publishes a repository containing a file named None.py. When no custom_pipeline argument is supplied, the loader's _resolve_custom_pipeline_and_cls formats the lookup to None.py and detects it as a custom pipeline, while download's gate does not detect None.py as custom code, so the file is imported and executed. Aliasing a naive pipeline class in None.py keeps the pipeline functional and hides the execution.[0]
  2. TOCTOU race condition (CVE-2026-45804): download fetches the config file first via hf_hub_download and runs the trust check against it, then fetches the rest of the repository via a separate snapshot_download call. With revision=None each call resolves the default branch's current HEAD, so an attacker who modifies the config to point to custom code within the ~0.3 second window between the two calls achieves execution, statistically succeeding across a popular repo's many daily downloads.[0]
  3. Custom-pipeline and local-snapshot variants (CVE-2026-44513): Cross-repo custom_pipeline points the model to repoA while the pipeline is imported from attacker-controlled repoB, evading the gate that checks repoA's file list. When the primary path is a local directory, from_pretrained never calls download at all, so the gate is never reached, and a local snapshot's model_index.json referencing a custom component file causes that component code to be loaded and executed.[0]

Disclosure timeline

DateEvent
March 19, 2026Zafran Labs reported the None.py Trust Remote Code Bypass and TOCTOU Trust Remote Code Bypass to Hugging Face.[0]
April 30, 2026Hugging Face released diffusers version 0.38.0 with the fixes.[0]
May 1-7, 2026Hugging Face acknowledged the findings and started the CVE assignment process.[0]
May 14, 2026CVE-2026-44827 published for the None.py Trust Remote Code Bypass.[0]
May 20, 2026CVE-2026-45804 published for the TOCTOU Trust Remote Code Bypass.[0]
July 16, 2026Hugging Face published disclosure of a July 2026 production infrastructure intrusion driven by an autonomous AI agent that abused dataset code-execution paths.[1]
July 27, 2026Zafran Labs published the FaceHugger research detailing the diffusers vulnerabilities.[0]

How it works

from_pretrained calls DiffusionPipeline.download, which serves as the trust_remote_code gatekeeper: it reads the configuration, decides whether the repo requests custom code, and raises a ValueError if custom code is present without trust_remote_code=True. The root cause of all variants is that this trust check lives entirely in the first phase, so any method that makes the loader see custom code the gate did not see bypasses the safeguard.[0]

For CVE-2026-44827, when custom_pipeline defaults to None, the check f"{custom_pipeline}.py" resolves to None.py; if such a file exists it is detected and loaded as a custom pipeline by _resolve_custom_pipeline_and_cls, even though download's gate uses different string handling and never flags None.py. Placing an aliased subclass of a real pipeline (e.g. FluxPipeline) in None.py keeps the pipeline functional while running arbitrary attacker code.[0]

For CVE-2026-45804, download performs hf_hub_download for the config and runs the trust check against it, then later calls snapshot_download for the rest of the repo. These are two independent HTTP operations that each resolve the branch HEAD when revision=None, so modifying the config to point to custom code in the roughly 0.3 second window between the calls yields execution. If all files are already cached, download returns early and the race window closes, so a first or forced download is required.[0]

A parallel flaw exists in the transformers package: after the config fetch resolves and pins a commit hash, some from_pretrained flows do not propagate that hash into get_class_from_dynamic_module, which re-resolves the commit and can pull a newer, attacker-added commit between the config fetch and the module fetch. A warning about the version change is printed but the code executes anyway.[0]

Affected versions and patch status

ProductAffectedPatch status
Hugging Face diffusers libraryVersions prior to 0.38.0Fixed in 0.38.0 (released April 30, 2026), which moves security checks to the dynamic-module loading chokepoint and closes the bypass variants.[0]
Hugging Face transformers libraryfrom_pretrained flows that fail to propagate the pinned commit hash into get_class_from_dynamic_moduleFlaw disclosed and acknowledged by Hugging Face's security team; no specific fixed version stated in the evidence.[0]

Key takeaways

  • A single misplaced trust check that runs only against the first of two non-atomic HTTP requests reintroduces a classic TOCTOU class of bug into widely adopted AI infrastructure, letting a routine model download become arbitrary code execution.[0]
  • trust_remote_code is not a sufficient safeguard on its own; the None.py, cross-repo, and local-snapshot variants each let attacker code execute without the gate ever detecting it.[0]
  • Given diffusers' ~200,000 daily installs and embedding in production, CI/CD, and container environments, even a short exploitation window can be exploited statistically across a large user base, making prompt patching to 0.38.0 and revision pinning essential.[0]
  • The parallel transformers flaw shows the same commit-pinning weakness spans multiple Hugging Face libraries, and a trusted repo's reputation may discourage clients from auditing transient malicious commits.[0]

Defensive actions

  • Upgrade the diffusers library to version 0.38.0 or later.: Version 0.38.0 moves the security checks to the dynamic-module loading chokepoint and closes the identified trust_remote_code bypass variants.[0]
  • Pin specific model repository revisions when loading remote models.: Pinning a revision prevents the TOCTOU race window where a repo's HEAD can change between the config fetch and the file fetch, ensuring consistency and blocking statistical-success attacks.[0]
  • Treat AI model repositories, configuration files, loaders, and custom pipeline code as untrusted executable code rather than passive data.: Artifacts from AI repositories can quietly cross into executable code, turning a routine model load into an initial-access vector, as demonstrated by both the diffusers flaws and Hugging Face's July 2026 incident.[0][1]