getredash/redash · error · ValueError

Scripts can only be run from the configured scripts…

Error message

Scripts can only be run from the configured scripts directory

What it means

Raised in ScriptQueryRunner.__init__ (redash/query_runner/script.py:65) as ValueError when the configured scripts path contains '../', i.e. it is not confined to a single directory. This is a deliberate path-traversal guard: the runner only permits executing scripts from one whitelisted directory, and any configuration that could escape it is rejected at construction time.

Solutions

  1. Set the path to the exact directory containing the scripts with no '../' segments (canonicalize it first: realpath)
  2. If you genuinely need multiple directories, use '*' with the understanding that it disables the confinement entirely
  3. Alternatively symlink the needed scripts into a single directory and configure that directory

Example fix

# before
path: /opt/redash/../shared/scripts
# after
path: /opt/shared/scripts
Defensive patterns

Strategy: validation

Validate before calling

import os.path
path = os.path.realpath(path)
if path != '*' and '..' + os.sep in path:
    raise ValueError('scripts path must not traverse parent directories')

Try / catch

try:
    runner = ScriptQueryRunner(configuration)
except ValueError as e:
    return error_response(400, 'Invalid scripts path: {}'.format(e))

Prevention

When it happens

Trigger: Saving a Script data source whose path setting includes a parent-directory segment, e.g. '/opt/redash/../scripts' or 'scripts/../../shared/scripts'. The only path that bypasses the check is the literal '*' (allow anything).

Common situations: Admins trying to point two data sources at a shared parent directory; symlinks not usable so '../' is attempted; mis-typed absolute path that accidentally contains a parent segment.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28). Data as JSON: /api/errors/77d8dd1f26466e44. Report an issue: GitHub.

Appendix: source

Thrown at redash/query_runner/script.py:65

            },
            "required": ["path"],
        }

    @classmethod
    def type(cls):
        return "insecure_script"

    def __init__(self, configuration):
        super(Script, self).__init__(configuration)

        path = self.configuration.get("path", "")
        # If path is * allow any execution path
        if path == "*":
            return

        # Poor man's protection against running scripts from outside the scripts directory
        if path.find("../") > -1:
            raise ValueError("Scripts can only be run from the configured scripts directory")

    def test_connection(self):
        pass

    def run_query(self, query, user):
        try:
            script = query_to_script_path(self.configuration["path"], query)
            return run_script(script, self.configuration["shell"])
        except IOError as e:
            return None, str(e)
        except subprocess.CalledProcessError as e:
            return None, str(e)


register(Script)

View on GitHub (pinned to ca79fe988d)