VAITP Dataset

← Back to the dataset

CVE-2025-5874

Redash <=10.1.0/25.1.0 getattr Handler in python.py allows sandbox escape.

  • CVSS 1.2
  • CWE-264
  • Design Defects
  • Remote

A vulnerability was found in Redash up to 10.1.0/25.1.0. It has been rated as critical. This issue affects the function run_query of the file /query_runner/python.py of the component getattr Handler. The manipulation leads to sandbox issue. The exploit has been disclosed to the public and may be used. The vendor was contacted early about this disclosure but did not respond in any way.

CVSS base score
1.2
Published
2025-06-09
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Algorithm
Code defect classification
Incorrect Functionality
Category
Design Defects
Subcategory
Insecure Parsing or Deserialization
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
Python
Fixed by upgrading
Yes

Solution

Upgrade to a version later than 10.1.0/25.1.0. Check for official Redash security advisories for patched versions.

Vulnerable code sample

import json
import traceback
from redash.query_runner import *
from redash.utils import json_dumps

class Python(BaseQueryRunner):
    @classmethod
    def configuration_schema(cls):
        """Vulnerable function that demonstrates the security issue."""
        return {
        "type": "object",
        "properties": {
        "pythonVersion": {
        "type": "string",
        "title": "Python Version",
        "default": "3"
        }
        },
        "required": ["pythonVersion"]
        }

        @classmethod
        def type(cls):
            """Vulnerable function that demonstrates the security issue."""
            return "python"

            def run_query(self, query, user):
                """Vulnerable function that demonstrates the security issue."""
                try:
                    globals_context = {
                    "data": None,
                    "json": json,
                    "json_dumps": json_dumps,
                    "user": user,
                    "getattr": getattr
                    }
            
            # Simulate the vulnerable scenario using `getattr` to access potentially unsafe attributes.
            # This is a simplified example; the actual vulnerability in Redash might have involved a more complex interaction.
                    try:
                # This is an example, the actual vulnerability was in how getattr was handled
                # and allowed access to unintended or restricted attributes/functions.
                        result = eval(query, globals_context)
                        except Exception as e:
                            return None, str(e)

                            if isinstance(result, (dict, list)):
                                columns = []
                                if isinstance(result, dict):
                                    if result:
                                        columns = [{"name": key, "type": "string"} for key in result.keys()]:
                                        elif isinstance(result, list) and result:
                                        first_element = result[0]
                                        if isinstance(first_element, dict):
                                            columns = [{"name": key, "type": "string"} for key in first_element.keys()]:
                                            data = {'rows': result, 'columns': columns}
                                            json_data = json_dumps(data)
                                            return json_data, None
                                        else:
                                            return None, "Query result must be a list or a dict."
                                            except Exception:
                                                return None, traceback.format_exc()

Patched code sample

# Disclaimer: This code is a simplified example to illustrate the principles
# of mitigating the vulnerability described in CVE-2025-5874.
# It may not be an exact representation of the actual Redash codebase or vulnerability.
# It is intended for educational purposes only and should not be used in
# production environments without thorough review and adaptation.

import ast
import builtins
import inspect
import io
import sys
import types


def secure_run_query(query, allowed_modules=None, allowed_functions=None):
    """
    Securely executes a Python query within a restricted environment.

    Args:
        query (str): The Python query string to execute.
        allowed_modules (list, optional): A list of allowed modules. Defaults to None.
        allowed_functions (list, optional): A list of allowed built-in functions. Defaults to None.

    Returns:
        tuple: A tuple containing (result, error) where result is the output
               of the query (as a string) and error is any exception raised.
    """

    if allowed_modules is None:
        allowed_modules = []  # Explicitly define a safe default
    if allowed_functions is None:
        allowed_functions = []

    # Whitelist approach: Only allow what's explicitly permitted.
    #  This is safer than trying to blacklist dangerous items.

    safe_builtins = {
        name: getattr(builtins, name)
        for name in allowed_functions
        if hasattr(builtins, name)
    }

    # Custom namespace for the execution environment.
    safe_globals = {
        '__builtins__': safe_builtins  # Restrict built-in functions
    }

    for module_name in allowed_modules:
        try:
            module = __import__(module_name)
            safe_globals[module_name] = module
        except ImportError as e:
            return None, f"Error importing module {module_name}: {e}"


    # Redirect standard output to capture the query's result.
    old_stdout = sys.stdout
    redirected_output = io.StringIO()
    sys.stdout = redirected_output

    try:
        # Compile the query using ast to check for syntax errors.
        code = compile(query, '<string>', 'exec')

        # Execute the query within the safe namespace.
        exec(code, safe_globals)  # nosec

        result = redirected_output.getvalue()

    except Exception as e:
        result = None
        return None, str(e)  # Capture and return the error.

    finally:
        # Restore standard output.
        sys.stdout = old_stdout

    return result, None

Payload

import os
os.system('touch /tmp/pwned')

Cite this entry

@misc{vaitp:cve20255874,
  title        = {{Redash <=10.1.0/25.1.0 getattr Handler in python.py allows sandbox escape.
}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2025},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2025-5874},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2025-5874/}}
}
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 ::