fix(cli): stop leaking API keys to CLI app subprocesses
Installed CLI apps were started with os.environ.copy(), so provider keys from the parent process were visible to untrusted binaries. Use a minimal allowlist env matching the shell tool. Fixes #4783
This commit is contained in:
@@ -990,7 +990,36 @@ class CliAppManager:
|
||||
return None
|
||||
raise CliAppError("this CLI app uses an unsupported install strategy")
|
||||
|
||||
def _run_argv(self, argv: list[str], *, timeout: int) -> subprocess.CompletedProcess[str]:
|
||||
def _subprocess_env(self) -> dict[str, str]:
|
||||
"""Minimal env for CLI app subprocesses — no API keys or secrets.
|
||||
|
||||
Mirrors the shell tool's allowlist so installed apps cannot read
|
||||
provider credentials from the parent process environment.
|
||||
"""
|
||||
if sys.platform == "win32":
|
||||
sr = os.environ.get("SYSTEMROOT", r"C:\Windows")
|
||||
env = {
|
||||
"SYSTEMROOT": sr,
|
||||
"COMSPEC": os.environ.get("COMSPEC", f"{sr}\\system32\\cmd.exe"),
|
||||
"USERPROFILE": os.environ.get("USERPROFILE", ""),
|
||||
"HOMEDRIVE": os.environ.get("HOMEDRIVE", "C:"),
|
||||
"HOMEPATH": os.environ.get("HOMEPATH", "\\"),
|
||||
"TEMP": os.environ.get("TEMP", f"{sr}\\Temp"),
|
||||
"TMP": os.environ.get("TMP", f"{sr}\\Temp"),
|
||||
"PATHEXT": os.environ.get("PATHEXT", ".COM;.EXE;.BAT;.CMD"),
|
||||
"PATH": os.environ.get("PATH", f"{sr}\\system32;{sr}"),
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
}
|
||||
return {k: v for k, v in env.items() if v is not None}
|
||||
return {
|
||||
"HOME": os.environ.get("HOME", "/tmp"),
|
||||
"LANG": os.environ.get("LANG", "C.UTF-8"),
|
||||
"TERM": os.environ.get("TERM", "dumb"),
|
||||
"PATH": os.environ.get("PATH", "/usr/bin:/bin"),
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
}
|
||||
|
||||
def _run_argv(self, argv: list[str], *, timeout: int) -> subprocess.CompletedProcess[str]:
|
||||
command = subprocess.list2cmdline(argv)
|
||||
logger.info("CLI Apps: running {}", command)
|
||||
result = subprocess.run(
|
||||
@@ -1431,7 +1460,7 @@ Use the `run_cli_app` tool with `name="{name}"` for command execution. Do not in
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
timeout=effective_timeout,
|
||||
env=os.environ.copy(),
|
||||
env=self._subprocess_env(),
|
||||
)
|
||||
except subprocess.TimeoutExpired:
|
||||
return f"CLI app '{name}' timed out after {effective_timeout}s"
|
||||
|
||||
Reference in New Issue
Block a user