The Vulnerability

Zafran Labs discovered that Hugging Face's diffusers library — with ~200,000 daily installations — has a fundamental flaw in how it enforces the trust_remote_code security boundary. Three CVEs were assigned:

All share the same root cause: the security check happens in a different phase than code execution.

How trust_remote_code Works

When loading a model with custom pipelines, diffusers checks if the repository contains custom code:

from diffusers import DiffusionPipeline

This triggers the trust check

pipe = DiffusionPipeline.from_pretrained( "stable-diffusion-v1-5/stable-diffusion-v1-5", custom_pipeline="text-to-video", trust_remote_code=False )

If trust_remote_code=False (or omitted), the loader should refuse to execute custom code.

The TOCTOU Flaw (CVE-2026-45804)

The root cause: from_pretrained() splits the operation into two non-atomic HTTP requests:

# Phase 1: Download config and CHECK for custom code
config = hf_hub_download(repo_id, "config.json")

trust_remote_code check happens HERE

Phase 2: Download the actual model files

snapshot_download(repo_id)

Code execution happens HERE

The window between Phase 1 and Phase 2 is exploitable:

Timeline:
  t0: Config downloaded, trust check passes (no custom code)
  t1: Attacker pushes malicious pipeline.py to repo
  t2: snapshot_download fetches and executes the malicious code

Window: ~0.3 seconds locally, but can be wider with slow connections or cache invalidation.

Exploitation

# Attacker controls a model repo

1. Initial commit: clean config, no custom code

2. Victim loads model -> trust check passes

3. Attacker pushes pipeline.py between the two HTTP calls

4. snapshot_download executes the malicious code

The None.py Bypass (CVE-2026-44827)

A simpler attack: name the malicious file None.py.

# The gate in download() checks:

f"{custom_pipeline}.py" in filenames

This looks for "pipeline.py" — misses "None.py"

But the loader resolves and imports None.py anyway

The security check and code execution use different resolution logic.

The Cross-Repo Variant (CVE-2026-44513)

# Attacker creates:

- repoA: clean config, no custom code

- repoB: malicious pipeline.py

Victim loads:

pipe = DiffusionPipeline.from_pretrained( "repoA", # trust check runs against repoA custom_pipeline="repoB/pipeline", # code fetched from repoB )

The trust gate evaluates against repoA's file list. The pipeline is fetched from repoB. The gate never sees the malicious code.

Impact

Remediation

Update to diffusers >= 0.38.0 (released May 2026):

pip install diffusers>=0.38.0

Additional protections:

  1. Always pin specific revisions when loading from Hub
  2. Never use custom_pipeline pointing to a different repo
  3. Inspect local snapshots before loading
  4. Use trust_remote_code=False (already default, but be explicit)

Lessons

  1. Security checks must be atomic with the operations they protect
  2. TOCTOU in package managers is a critical supply chain risk
  3. AI libraries need the same scrutiny as traditional package managers
  4. trust_remote_code is not enough if the enforcement is flawed

Based on Zafran Labs disclosure and CVE-2026-44827, CVE-2026-45804, CVE-2026-44513.