From 535b5fb1bf6c509884be86bf4dc6816f0a294e52 Mon Sep 17 00:00:00 2001 From: ZdenekSrotyr Date: Thu, 9 Apr 2026 06:58:26 +0200 Subject: [PATCH] security: strip VIRTUAL_ENV/PYTHONPATH from script sandbox and block httpx Replace inherited env vars with a minimal env dict (PATH, DATA_DIR, HOME only), omitting VIRTUAL_ENV and PYTHONPATH to prevent subprocess access to installed packages. Switch subprocess invocation to sys.executable so the correct interpreter is used with the restricted PATH. Add httpx to blocked_patterns and BLOCKED_MODULES. Add test_sandbox_cannot_import_httpx to test_security.py. --- app/api/scripts.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/api/scripts.py b/app/api/scripts.py index 10cf0fa..838a90d 100644 --- a/app/api/scripts.py +++ b/app/api/scripts.py @@ -2,6 +2,7 @@ import os import subprocess +import sys import tempfile import uuid from pathlib import Path @@ -119,6 +120,7 @@ def _execute_script(source: str, name: str) -> dict: "import importlib", "from importlib", "import socket", "from socket", "import requests", "from requests", + "import httpx", "from httpx", "import urllib", "from urllib", "import http", "from http", # Dynamic import bypasses @@ -146,7 +148,7 @@ def _execute_script(source: str, name: str) -> dict: import ast BLOCKED_MODULES = {"os", "sys", "subprocess", "shutil", "ctypes", "importlib", "socket", - "requests", "urllib", "http", "signal", "pathlib", "builtins"} + "requests", "httpx", "urllib", "http", "signal", "pathlib", "builtins"} BLOCKED_FUNCTIONS = {"exec", "eval", "compile", "open", "globals", "locals", "getattr", "setattr", "delattr", "breakpoint", "__import__"} @@ -184,17 +186,16 @@ def _execute_script(source: str, name: str) -> dict: try: result = subprocess.run( - ["python", script_path], + [sys.executable, script_path], capture_output=True, text=True, timeout=SCRIPT_TIMEOUT, env={ - "PATH": os.environ.get("PATH", ""), - "PYTHONPATH": os.environ.get("PYTHONPATH", ""), + "PATH": "/usr/bin:/usr/local/bin", "DATA_DIR": data_dir, "HOME": "/tmp", - # Pass through Python env for package discovery - "VIRTUAL_ENV": os.environ.get("VIRTUAL_ENV", ""), + # Deliberately exclude VIRTUAL_ENV and PYTHONPATH + # to prevent access to installed packages }, cwd="/tmp", # restrict working directory )