From 06169c2acbfbdcbc5a903321fea42671704f6be3 Mon Sep 17 00:00:00 2001 From: badMade <106821302+badMade@users.noreply.github.com> Date: Wed, 3 Jun 2026 00:54:04 +0000 Subject: [PATCH 1/2] Sanitize subprocess environments in tools_config.py This commit introduces environment sanitization for all subprocess calls within `hermes_cli/tools_config.py` to prevent sensitive environment variables (like API keys and tokens) from leaking into external tools (npm, pip, Chromium/cua-driver installers). Key changes: - Imported `_sanitize_subprocess_env` from `tools.environments.local`. - Updated `_pip_install` to sanitize `uv_env` and standard `pip` calls. - Applied sanitization to `npm install`, Chromium install, Camofox install, and `cua-driver` setup calls. - Ensured `os.environ.copy()` is used to prevent side effects. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- hermes_cli/tools_config.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/hermes_cli/tools_config.py b/hermes_cli/tools_config.py index 614e79b43d4e..e67863395369 100644 --- a/hermes_cli/tools_config.py +++ b/hermes_cli/tools_config.py @@ -28,6 +28,7 @@ apply_nous_managed_defaults, get_nous_subscription_features, ) +from tools.environments.local import _sanitize_subprocess_env from tools.tool_backend_helpers import fal_key_is_configured, managed_nous_tools_enabled from utils import base_url_hostname, is_truthy_value @@ -584,7 +585,7 @@ def _pip_install( (or the last failure for the caller to inspect). """ venv_root = Path(sys.executable).parent.parent - uv_env = {**os.environ, "VIRTUAL_ENV": str(venv_root)} + uv_env = _sanitize_subprocess_env(os.environ.copy(), {"VIRTUAL_ENV": str(venv_root)}) uv_bin = shutil.which("uv") if uv_bin: @@ -607,6 +608,7 @@ def _pip_install( probe = subprocess.run( pip_cmd + ["--version"], capture_output=True, text=True, timeout=15, + env=_sanitize_subprocess_env(os.environ.copy()), ) if probe.returncode != 0: raise FileNotFoundError("pip not in venv") @@ -615,6 +617,7 @@ def _pip_install( subprocess.run( [sys.executable, "-m", "ensurepip", "--upgrade", "--default-pip"], capture_output=True, text=True, timeout=120, check=True, + env=_sanitize_subprocess_env(os.environ.copy()), ) except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e: # Synthesize a result so callers see a clean failure path. @@ -626,6 +629,7 @@ def _pip_install( return subprocess.run( pip_cmd + ["install", *args], capture_output=capture_output, text=True, timeout=timeout, + env=_sanitize_subprocess_env(os.environ.copy()), ) @@ -646,7 +650,8 @@ def _run_post_setup(post_setup_key: str): # behaviour as before. result = subprocess.run( [npm_bin, "install", "--silent"], - capture_output=True, text=True, cwd=str(PROJECT_ROOT) + capture_output=True, text=True, cwd=str(PROJECT_ROOT), + env=_sanitize_subprocess_env(os.environ.copy()), ) if result.returncode == 0: _print_success(" Node.js dependencies installed") @@ -722,6 +727,7 @@ def _run_post_setup(post_setup_key: str): result = subprocess.run( install_cmd, capture_output=True, text=True, cwd=str(PROJECT_ROOT), timeout=600, + env=_sanitize_subprocess_env(os.environ.copy()), ) if result.returncode == 0: _print_success(" Chromium installed") @@ -751,7 +757,8 @@ def _run_post_setup(post_setup_key: str): # Absolute npm path so .cmd shim executes on Windows. result = subprocess.run( [_npm_bin, "install", "--silent"], - capture_output=True, text=True, cwd=str(PROJECT_ROOT) + capture_output=True, text=True, cwd=str(PROJECT_ROOT), + env=_sanitize_subprocess_env(os.environ.copy()), ) if result.returncode == 0: _print_success(" Camofox installed") @@ -779,6 +786,7 @@ def _run_post_setup(post_setup_key: str): version = subprocess.run( ["cua-driver", "--version"], capture_output=True, text=True, timeout=5, + env=_sanitize_subprocess_env(os.environ.copy()), ).stdout.strip() _print_success(f" cua-driver already installed: {version or 'unknown version'}") except Exception: @@ -798,7 +806,12 @@ def _run_post_setup(post_setup_key: str): "https://raw.githubusercontent.com/trycua/cua/main/" "libs/cua-driver/scripts/install.sh)\"" ) - result = subprocess.run(install_cmd, shell=True, timeout=300) + result = subprocess.run( + install_cmd, + shell=True, + timeout=300, + env=_sanitize_subprocess_env(os.environ.copy()), + ) if result.returncode == 0 and shutil.which("cua-driver"): _print_success(" cua-driver installed.") _print_info(" IMPORTANT — grant macOS permissions now:") From 7a51cd2ec30b85c24b96ec9e9ec919ca88843f01 Mon Sep 17 00:00:00 2001 From: badMade <106821302+badMade@users.noreply.github.com> Date: Wed, 3 Jun 2026 01:50:57 +0000 Subject: [PATCH 2/2] Sanitize subprocess environments in tools_config.py This commit introduces environment sanitization for all subprocess calls within `hermes_cli/tools_config.py` to prevent sensitive environment variables (like API keys and tokens) from leaking into external tools. To avoid circular dependency or initialization order issues that could affect environment context during tests, `_sanitize_subprocess_env` is imported lazily within the functions. Key changes: - Updated `_pip_install` to sanitize `uv_env` and standard `pip` calls. - Applied sanitization to `npm install`, Chromium install, Camofox install, and `cua-driver` setup calls in `_run_post_setup`. - Ensured `os.environ.copy()` is used to prevent side effects. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> --- hermes_cli/tools_config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hermes_cli/tools_config.py b/hermes_cli/tools_config.py index e67863395369..6a0672392f27 100644 --- a/hermes_cli/tools_config.py +++ b/hermes_cli/tools_config.py @@ -28,7 +28,6 @@ apply_nous_managed_defaults, get_nous_subscription_features, ) -from tools.environments.local import _sanitize_subprocess_env from tools.tool_backend_helpers import fal_key_is_configured, managed_nous_tools_enabled from utils import base_url_hostname, is_truthy_value @@ -568,6 +567,7 @@ def _pip_install( timeout: int = 300, capture_output: bool = True, ): + from tools.environments.local import _sanitize_subprocess_env """Install Python packages from a post-setup hook. Strategy (in order): @@ -636,6 +636,7 @@ def _pip_install( def _run_post_setup(post_setup_key: str): """Run post-setup hooks for tools that need extra installation steps.""" import shutil + from tools.environments.local import _sanitize_subprocess_env if post_setup_key in {"agent_browser", "browserbase"}: node_modules = PROJECT_ROOT / "node_modules" / "agent-browser" npm_bin = shutil.which("npm")