VAITP Dataset

← Back to the dataset

CVE-2025-50460

RCE in ms-swift due to unsafe deserialization of YAML configuration files.

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

A remote code execution (RCE) vulnerability exists in the ms-swift project version 3.3.0 due to unsafe deserialization in tests/run.py using yaml.load() from the PyYAML library (versions = 5.3.1). If an attacker can control the content of the YAML configuration file passed to the –run_config parameter, arbitrary code can be executed during deserialization. This can lead to full system compromise. The vulnerability is triggered when a malicious YAML file is loaded, allowing the execution of arbitrary Python commands such as os.system(). It is recommended to upgrade PyYAML to version 5.4 or higher, and to use yaml.safe_load() to mitigate the issue.

CVSS base score
9.8
Published
2025-08-01
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Checking
Code defect classification
Serialization Issues
Category
Input Validation and Sanitization
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Local
Impact
Arbitrary Code Execution
Affected component
ms-swift
Fixed by upgrading
Yes

Solution

Upgrade PyYAML to version 5.4 or higher and replace `yaml.load()` with `yaml.safe_load()`.

Vulnerable code sample

# tests/run.py (Vulnerable Version)
# This code simulates the vulnerability described in CVE-2025-50460.
# It uses the insecure `yaml.load()` function on a user-controlled file.

import yaml
import argparse
import os  # This import is necessary for a payload like !!python/object/apply:os.system to work

def load_configuration(config_path):
    """
    Loads the test configuration from a specified YAML file.
    """
    print(f"[INFO] Loading configuration from: {config_path}")
    with open(config_path, 'r') as f:
        # VULNERABILITY: Use of unsafe yaml.load() on a file path controlled
        # by the --run_config parameter. A malicious actor can craft a
        # YAML file that executes arbitrary code upon being parsed.
        # In PyYAML < 5.4, `yaml.load` defaults to the unsafe FullLoader.
        config = yaml.load(f, Loader=yaml.FullLoader)
    print("[INFO] Configuration loaded successfully.")
    return config

def execute_run(config):
    """
    Placeholder function to simulate executing a run based on the configuration.
    """
    print("[INFO] Executing run with the following settings:")
    # In a real application, this would use the config data to perform actions.
    if config:
        for key, value in config.items():
            print(f"  - {key}: {value}")
    print("[INFO] Run finished.")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="ms-swift test runner"
    )
    parser.add_argument(
        '--run_config',
        type=str,
        required=True,
        help="Path to the YAML configuration file for the run."
    )
    args = parser.parse_args()

    try:
        configuration = load_configuration(args.run_config)
        if configuration:
             # The vulnerability is triggered during the load_configuration call.
             # If code execution occurs, the script might terminate or continue.
            execute_run(configuration)
    except Exception as e:
        print(f"[ERROR] An error occurred during execution: {e}")

Patched code sample

import yaml
import argparse
import sys
import os

# This code represents the fixed version of 'tests/run.py' from the
# ms-swift project, addressing the unsafe deserialization vulnerability.
#
# The vulnerability (CVE-2025-50460) existed because the original code used
# `yaml.load()`, which can execute arbitrary code from a malicious YAML file.
#
# The fix is to replace the unsafe `yaml.load()` with `yaml.safe_load()`.
# The `safe_load` function can parse basic YAML tags but restricts it to
# simple Python objects like integers, strings, lists, and dictionaries,
# preventing the execution of arbitrary code.

def run_tests_fixed(config_path):
    """
    Loads a test configuration from a YAML file and runs tests.
    This version uses the secure yaml.safe_load() method.
    """
    if not os.path.exists(config_path):
        print(f"Error: Configuration file not found at '{config_path}'")
        sys.exit(1)

    print(f"Loading configuration securely from: {config_path}")
    try:
        with open(config_path, 'r') as f:
            # FIX: Using yaml.safe_load() instead of the vulnerable yaml.load().
            # yaml.safe_load() parses the YAML document without executing any
            # code, effectively mitigating the RCE vulnerability.
            config = yaml.safe_load(f)

        print("Configuration loaded successfully and safely.")
        print(f"Config content: {config}")
        # In a real application, test execution logic would follow.
        # For demonstration, we just print the loaded config.

    except yaml.YAMLError as e:
        print(f"Error parsing YAML file: {e}")
        # If a malicious payload like '!!python/object/apply:os.system'
        # is present, safe_load will raise a YAMLError (ConstructorError)
        # instead of executing the command.
        print("The provided YAML file may contain unsafe constructs not allowed by safe_load.")
        sys.exit(1)


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="Fixed test runner for ms-swift project. Demonstrates the fix for CVE-2025-50460."
    )
    parser.add_argument(
        '--run_config',
        required=True,
        help='Path to the YAML configuration file.'
    )
    args = parser.parse_args()

    run_tests_fixed(args.run_config)

# To test this fix, you can create two YAML files.
#
# 1. A safe configuration file (e.g., 'safe_config.yaml'):
# ---
# test_suite: 'smoke_tests'
# parameters:
#   retries: 3
#   timeout: 60
#
# Command: python fixed_run.py --run_config safe_config.yaml
# Expected Output: The script will load and print the configuration dictionary.
#
# 2. A malicious configuration file (e.g., 'malicious_config.yaml'):
# ---
# !!python/object/apply:os.system
# - "echo 'This command should NOT be executed.'"
#
# Command: python fixed_run.py --run_config malicious_config.yaml
# Expected Output: The script will raise a YAMLError and exit, preventing
#                  the command from being executed. This demonstrates the
#                  vulnerability has been mitigated.

Payload

!!python/object/apply:os.system
- 'touch /tmp/pwned'

Cite this entry

@misc{vaitp:cve202550460,
  title        = {{RCE in ms-swift due to unsafe deserialization of YAML configuration files.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2025},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2025-50460},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-50460/}}
}
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 ::