AI and data stack advisories

Severe, 6 weeks1498Projects326

1498 severe, 6 weeks · 326 projects

diffusersGHSA-7wx4-6vff-v64p

Diffusers: TOCTOU Trust Remote Code Bypass

diffusers

CVE-2026-45804 · Published May 20, 2026 · updated Sep 10, 2026

High7.5
Fix: upgrade to 0.38.0 or later
GitHub advisory

Background

This vulnerability is found in the diffusers package - the transformers-equivalent library for diffusion models.

It is found in the DiffusionPipeline.from_pretrained flow, which is used to load a pipeline from the HuggingFace Hub.

This function has a trust_remote_code guard: if the repository’s model_index.json references a custom pipeline class defined in a .py file in the repo, the load is blocked unless trust_remote_code=True is explicitly passed:

`

ValueError: The repository for attacker/repo contains custom code in pipeline.py

which must be executed to correctly load the model. You can inspect the repository

content at https://hf.co/attacker/repo/blob/main/pipeline.py.

Please pass the argument trust_remote_code=True to allow custom code to be run.

`

The vulnerability allows arbitrary code execution through the custom pipeline flow from a Hub repo, with no custom_pipeline or trust_remote_code kwargs passed. The from_pretrained call succeeds and returns a functional pipeline.

---

Naive Flow

DiffusionPipeline.from_pretrained begins by popping all relevant arguments from kwargs into local variables, then calls DiffusionPipeline.download() to fetch the repo files:

```python

pipeline_utils.py:853

cached_folder = cls.download(

pretrained_model_name_or_path,

...

custom_pipeline=custom_pipeline,...

Affected versions

PackageAffectedFixed in
diffusers
PyPI
< 0.38.00.38.0
Details and references

## Background This vulnerability is found in the `diffusers` package - the `transformers`-equivalent library for diffusion models. It is found in the `DiffusionPipeline.from_pretrained` flow, which is used to load a pipeline from the HuggingFace Hub. This function has a `trust_remote_code` guard: if the repository’s `model_index.json` references a custom pipeline class defined in a `.py` file in the repo, the load is blocked unless `trust_remote_code=True` is explicitly passed: ``` ValueError: The repository for attacker/repo contains custom code in pipeline.py which must be executed to correctly load the model. You can inspect the repository content at https://hf.co/attacker/repo/blob/main/pipeline.py. Please pass the argument `trust_remote_code=True` to allow custom code to be run. ``` The vulnerability allows arbitrary code execution through the custom pipeline flow from a Hub repo, with no `custom_pipeline` or `trust_remote_code` kwargs passed. The `from_pretrained` call succeeds and returns a functional pipeline. --- ## Naive Flow `DiffusionPipeline.from_pretrained` begins by popping all relevant arguments from `kwargs` into local variables, then calls `DiffusionPipeline.download()` to fetch the repo files: ```python # pipeline_utils.py:853 cached_folder = cls.download( pretrained_model_name_or_path, ... custom_pipeline=custom_pipeline, trust_remote_code=trust_remote_code, ... ) ``` Inside `download()`, `model_index.json` is fetched first as a standalone file via `hf_hub_download`: ```python # pipeline_utils.py:1636 config_file = hf_hub_download( pretrained_model_name, cls.config_name, ... ) config_dict = cls._dict_from_json_file(config_file) ``` This config is used to detect custom pipeline code and enforce the trust check: ```python # pipeline_utils.py:1672 if custom_pipeline is None and isinstance(config_dict["_class_name"], (list, tuple)): custom_pipeline = config_dict["_class_name"][0] load_pipe_from_hub = custom_pipeline is not None and f"{custom_pipeline}.py" in filenames if load_pipe_from_hub and not trust_remote_code: raise ValueError(...) ``` After the check passes, `snapshot_download` then fetches all files and saves them to disk: ```python # pipeline_utils.py:1778 cached_folder = snapshot_download( pretrained_model_name, ... revision=revision, allow_patterns=allow_patterns, ... ) ``` Back in `from_pretrained`, the config is read a second time from the downloaded snapshot, and`_resolve_custom_pipeline_and_cls` reads the config to re-check if custom code needs to be loaded: ```python # pipeline_loading_utils.py:974 def _resolve_custom_pipeline_and_cls(folder, config, custom_pipeline): custom_class_name = None if os.path.isfile(os.path.join(folder, f"{custom_pipeline}.py")): custom_pipeline = os.path.join(folder, f"{custom_pipeline}.py") elif isinstance(config["_class_name"], (list, tuple)) and os.path.isfile( os.path.join(folder, f"{config['_class_name'][0]}.py") ): custom_pipeline = os.path.join(folder, f"{config['_class_name'][0]}.py") custom_class_name = config["_class_name"][1] return custom_pipeline, custom_class_name ``` If the config points to a `.py` file, it is imported. --- ## The Vulnerability `hf_hub_download` and `snapshot_download` are two independent HTTP calls to the Hub, both resolving the repository’s default branch (if `revision=None`) to its current HEAD at call time. There is no atomicity guarantee between them - if the repository is updated between the two calls, they will resolve to different commits and download different content, with no warning displayed to the user. The trust check in `download()` operates on the content fetched by `hf_hub_download` (commit A). The `snapshot_download` call that immediately follows can silently fetch a newer commit (commit B). The config in the newer commit will be the one parsed by `_resolve_custom_pipeline_and_cls`.

CVSS 3.1
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
Severity from
GitHub (reviewed advisory)
Weakness
CWE-367
Also known as
CVE-2026-45804, PYSEC-2026-2446

More diffusers advisories

All diffusers