From db38311a8d78a23eecab7094b59f49e5ca35032b Mon Sep 17 00:00:00 2001 From: ciregenz Date: Wed, 13 May 2026 13:20:19 -0700 Subject: [PATCH] [eric] fix prod regressions: __import__ scrub broke imports + Windows path gate --- backend/apps/agents/agent_manager.py | 9 +++++++++ backend/apps/outputs/executor.py | 15 +++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/backend/apps/agents/agent_manager.py b/backend/apps/agents/agent_manager.py index 39a9bdb7..ffc355bb 100644 --- a/backend/apps/agents/agent_manager.py +++ b/backend/apps/agents/agent_manager.py @@ -1153,6 +1153,15 @@ class AgentManager: norm = os.path.normpath(os.path.expanduser(file_path)) except Exception: return False + # Normalize to forward slashes so the patterns match on Windows + # too — `os.path.normpath` produces backslashes on Windows + # (`C:\Users\eric\.ssh\authorized_keys`), and fnmatch treats + # `/` in the pattern as a literal character. Without this, + # every sensitive-path gate would silently no-op on Windows + # production and the prompt-injected `Write` to `~/.ssh/...` + # would go through unchallenged. + if os.sep != '/': + norm = norm.replace(os.sep, '/') for pat in _SENSITIVE_PATH_PATTERNS: if _fnmatch.fnmatch(norm, pat): return True diff --git a/backend/apps/outputs/executor.py b/backend/apps/outputs/executor.py index 01d62341..8b2d378f 100644 --- a/backend/apps/outputs/executor.py +++ b/backend/apps/outputs/executor.py @@ -184,10 +184,17 @@ async def execute_backend_code( preamble = ( "import json, sys, io, builtins\n" - # Defense-in-depth: even with an AST allowlist on the host, scrub - # dangerous attrs off `builtins` here so attribute-style accesses - # (e.g. via metaclass.__subclasses__ chains) can't reach them. - "for _b in ('exec','eval','compile','__import__','open','input',\n" + # Defense-in-depth: scrub dangerous attrs off `builtins` so + # attribute-style accesses (metaclass.__subclasses__ chains) can't + # reach them. NOTE: __import__ is deliberately NOT scrubbed — + # Python's `import` statement bytecode reads `__import__` from + # builtins, so removing it makes EVERY import (including allowlisted + # ones like `import math`) fail with "ImportError: __import__ not + # found". The AST allowlist on the host is what blocks `import + # subprocess`; the per-subprocess scrub just plugs the named-builtin + # attack vectors that the AST can't see (eval/exec via attribute + # access on objects, etc.). + "for _b in ('exec','eval','compile','open','input',\n" " 'breakpoint','exit','quit'):\n" " try: delattr(builtins, _b)\n" " except AttributeError: pass\n"