fix(cli,tui-gateway): sanitize env and redact output in exec quick commands

HermesCLI.process_command() and tui_gateway command.dispatch both handle
type: exec quick commands via subprocess.run(shell=True) with no env=
parameter, so the child inherits the full process environment — all API
keys and bot tokens stored in os.environ are visible to the script.
Any output is returned raw to the terminal or web-UI client without
redaction.

Fix: mirror the approach applied to gateway/run.py in #23584.
Apply _sanitize_subprocess_env() before spawning the subprocess and
redact_sensitive_text() on the collected output before display.
Symmetric across all three exec quick-command paths.

Parity with gateway/run.py fix in #23584.
This commit is contained in:
EloquentBrush 2026-05-11 12:24:13 +03:00 committed by Teknium
parent 55d92516c8
commit c8e5f999c2
2 changed files with 17 additions and 1 deletions

9
cli.py
View file

@ -8600,12 +8600,19 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin):
try:
# shell=True is intentional: quick_commands are user-defined
# shell snippets from config.yaml — not agent/LLM controlled.
# Sanitize env to prevent credential leakage —
# quick commands run in the CLI process which
# has all API keys in os.environ.
from tools.environments.local import _sanitize_subprocess_env
sanitized_env = _sanitize_subprocess_env(os.environ.copy())
result = subprocess.run(
exec_cmd, shell=True, capture_output=True,
text=True, timeout=30
text=True, timeout=30, env=sanitized_env
)
output = result.stdout.strip() or result.stderr.strip()
if output:
from agent.redact import redact_sensitive_text
output = redact_sensitive_text(output)
self._console_print(_rich_text_from_ansi(output))
else:
self._console_print("[dim]Command returned no output[/]")

View file

@ -11310,6 +11310,11 @@ def _(rid, params: dict) -> dict:
if name in qcmds:
qc = qcmds[name]
if qc.get("type") == "exec":
# Sanitize env to prevent credential leakage —
# quick commands run in the TUI server process which
# has all API keys in os.environ.
from tools.environments.local import _sanitize_subprocess_env
sanitized_env = _sanitize_subprocess_env(os.environ.copy())
r = subprocess.run(
qc.get("command", ""),
shell=True,
@ -11317,12 +11322,16 @@ def _(rid, params: dict) -> dict:
text=True,
timeout=30,
stdin=subprocess.DEVNULL,
env=sanitized_env,
)
output = (
(r.stdout or "")
+ ("\n" if r.stdout and r.stderr else "")
+ (r.stderr or "")
).strip()[:4000]
if output:
from agent.redact import redact_sensitive_text
output = redact_sensitive_text(output)
if r.returncode != 0:
return _err(
rid,