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.
This commit is contained in:
ZdenekSrotyr 2026-04-09 06:58:26 +02:00
parent 3e9c347cf1
commit 535b5fb1bf

View file

@ -2,6 +2,7 @@
import os import os
import subprocess import subprocess
import sys
import tempfile import tempfile
import uuid import uuid
from pathlib import Path from pathlib import Path
@ -119,6 +120,7 @@ def _execute_script(source: str, name: str) -> dict:
"import importlib", "from importlib", "import importlib", "from importlib",
"import socket", "from socket", "import socket", "from socket",
"import requests", "from requests", "import requests", "from requests",
"import httpx", "from httpx",
"import urllib", "from urllib", "import urllib", "from urllib",
"import http", "from http", "import http", "from http",
# Dynamic import bypasses # Dynamic import bypasses
@ -146,7 +148,7 @@ def _execute_script(source: str, name: str) -> dict:
import ast import ast
BLOCKED_MODULES = {"os", "sys", "subprocess", "shutil", "ctypes", "importlib", "socket", 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", BLOCKED_FUNCTIONS = {"exec", "eval", "compile", "open", "globals", "locals",
"getattr", "setattr", "delattr", "breakpoint", "__import__"} "getattr", "setattr", "delattr", "breakpoint", "__import__"}
@ -184,17 +186,16 @@ def _execute_script(source: str, name: str) -> dict:
try: try:
result = subprocess.run( result = subprocess.run(
["python", script_path], [sys.executable, script_path],
capture_output=True, capture_output=True,
text=True, text=True,
timeout=SCRIPT_TIMEOUT, timeout=SCRIPT_TIMEOUT,
env={ env={
"PATH": os.environ.get("PATH", ""), "PATH": "/usr/bin:/usr/local/bin",
"PYTHONPATH": os.environ.get("PYTHONPATH", ""),
"DATA_DIR": data_dir, "DATA_DIR": data_dir,
"HOME": "/tmp", "HOME": "/tmp",
# Pass through Python env for package discovery # Deliberately exclude VIRTUAL_ENV and PYTHONPATH
"VIRTUAL_ENV": os.environ.get("VIRTUAL_ENV", ""), # to prevent access to installed packages
}, },
cwd="/tmp", # restrict working directory cwd="/tmp", # restrict working directory
) )