Skip to content

fix(security): close kanban worker auto-approve gap for dangerous commands - #54

Open
hashbender wants to merge 1 commit into
mainfrom
mirror/pr-55946
Open

fix(security): close kanban worker auto-approve gap for dangerous commands#54
hashbender wants to merge 1 commit into
mainfrom
mirror/pr-55946

Conversation

@hashbender

Copy link
Copy Markdown
Owner

What

Kanban-dispatched worker subprocesses — the primary execution vehicle for long-horizon, unattended multi-agent work in Hermes — fall through every approval-context check in tools/approval.py and silently auto-approve any non-hardline dangerous command, with only a logger.warning() left behind.

Why

Same bug class as NousResearch#30882 (P0, fixed in NousResearch#34497): an execution surface the approval system doesn't recognize defaults to trusted-by-omission instead of trusted-by-explicit-config. That fix's own description states the philosophy plainly: "The approval gate is a documented heuristic in SECURITY.md, not a security boundary; this restores its intended behavior — it doesn't add one."

Unlike NousResearch#30882 (a ContextVar-propagation regression in threads), this is a plain omission, not a regression — kanban workers are separate subprocess processes (not threads sharing contextvars), and the approval-context question was simply never wired in when kanban dispatch was built.

hermes_cli/kanban_db.py's worker-spawn env construction (_default_spawn) sets 15+ environment variables (HERMES_KANBAN_TASK, HERMES_KANBAN_WORKSPACE, etc.) but never any of the four flags tools/approval.py checks to recognize a non-interactive context: HERMES_CRON_SESSION, HERMES_GATEWAY_SESSION, HERMES_SESSION_PLATFORM, HERMES_INTERACTIVE. All three approval-gate functions (check_dangerous_command, check_all_command_guards, check_execute_code_guard) therefore fall through to the bare non-interactive auto-approve branch.

Change

Mirrors the proven cron_mode pattern exactly — not a new mechanism:

  • HERMES_KANBAN_SESSION env flag set at worker spawn time (hermes_cli/kanban_db.py)
  • approvals.kanban_mode config, default deny (matching cron_mode's default)
  • _get_kanban_approval_mode() mirrors _get_cron_approval_mode() verbatim
  • A parallel deny-by-default branch added to all three call sites in tools/approval.py, alongside the existing cron branch — not replacing it
  • approvals.kanban_mode: approve remains available for users who've deliberately decided to trust their kanban workers, same as cron_mode

kanban_mode lives under approvals (not the kanban: config block) — that block has a known, separately-filed duplicate-key bug (NousResearch#55779) that silently drops the first of two "kanban" keys in the same DEFAULT_CONFIG dict literal.

How to test

python -m pytest tests/tools/test_kanban_approval_mode.py tests/tools/test_cron_approval_mode.py tests/tools/test_execute_code_approval_cluster.py tests/tools/test_approval.py -v

Verified against the real, unmodified functions (not mocked) before writing any fix code:

# Real env captured from kanban_db._default_spawn() via a real task in a
# scratch kanban DB (subprocess.Popen intercepted, not launched):
captured_env["HERMES_CRON_SESSION"]      # None
captured_env["HERMES_GATEWAY_SESSION"]   # None
captured_env["HERMES_SESSION_PLATFORM"]  # None
captured_env["HERMES_INTERACTIVE"]       # None

# Feeding that exact env into a fresh process and calling the real,
# unmodified check_dangerous_command():
check_dangerous_command("chmod 777 /some/file", env_type="local")
# main (pre-fix):  {'approved': True, 'message': None}  -- silent auto-approve
# this PR (post-fix): {'approved': False, 'message': 'BLOCKED: ...'}
# approvals.kanban_mode: approve restores the opt-in pass-through
  • All 19 new tests in test_kanban_approval_mode.py pass; all pre-existing cron/CLI/gateway tests across the 4 touched test files stay byte-stable when run per-file (matching scripts/run_tests.sh's per-file isolation).
  • scripts/check-windows-footguns.py clean on the diff (pure env-var/config logic).

Platforms tested

macOS (logic-only change, no OS-specific code paths — pure env-var/config string matching).

Note

While testing I found an unrelated, pre-existing test-isolation issue (test_cron_approval_mode.py + test_approval.py leak shared module state when run together in one pytest process — confirmed on unmodified main too, invisible to CI because scripts/run_tests.sh isolates each test file into its own subprocess). Filed separately, not part of this diff.

Fixes NousResearch#55945


Mirror-of: NousResearch#55946
NousResearch#55946

@tenki-reviewer

tenki-reviewer Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Complete
No issues found!

Risk: 🔴 Critical (82/100) — no findings · 374 LOC across 7 files


PR adds kanban approval mode support but the subprocess environment construction has four security/correctness gaps: HERMES_EXEC_ASK leaks from the gateway bypassing kanban deny guards, HERMES_CRON_SESSION leaks from the cron scheduler overriding kanban mode, credentials leak via unsanitized os.environ copy, and _is_gateway_approval_context() misses a HERMES_KANBAN_SESSION exclusion.

Files Reviewed (7 files)
hermes_cli/config.py
hermes_cli/kanban_db.py
tests/conftest.py
tests/tools/test_approval.py
tests/tools/test_execute_code_approval_cluster.py
tests/tools/test_kanban_approval_mode.py
tools/approval.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Security] Kanban worker subprocesses silently auto-approve dangerous commands (no approval-context flag set)

1 participant