Skip to content

fix(approval): pair config.yaml write protection across file tools + terminal (#14639) - #36732

Merged
teknium1 merged 3 commits into
mainfrom
fix/14639-pair-hermes-config-write-protection
Jun 1, 2026
Merged

fix(approval): pair config.yaml write protection across file tools + terminal (#14639)#36732
teknium1 merged 3 commits into
mainfrom
fix/14639-pair-hermes-config-write-protection

Conversation

@teknium1

@teknium1 teknium1 commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

The bug (verified live on main)

~/.hermes/config.yaml holds the security policy itself — approvals.mode, yolo state, the permanent-approval allowlist. The config cache is mtime+size keyed (hermes_cli/config.py:_load_config_impl), so a write invalidates it and the next _get_approval_mode() call re-reads from disk mid-session. A prompt-injected or misguided agent can therefore set approvals.mode: off and immediately bypass the dangerous-command gate on all subsequent calls.

Why the original PR (#14639) was necessary but not sufficient

@Subway2023's #14639 correctly adds a write_file/patch deny for ~/.hermes/config.yaml. But a tool-level write deny is only a real boundary when paired with equivalent terminal-side coverage (SECURITY.md §2.4 / paired-restriction rule) — otherwise the agent just uses the terminal tool.

I verified the terminal side on main: echo >, >>, tee, cp, mv to config.yaml already tripped the project-config pattern, but sed -i and sed --in-place slipped through with auto-approve. So #14639 alone would have left an open door.

What this PR does (salvage + pairing)

  1. Cherry-picks @Subway2023's commit (write_file/patch deny in tools/file_tools.py::_check_sensitive_path) — authorship preserved, conflict with current main resolved.
  2. Adds the terminal-side pairing (tools/approval.py): a _HERMES_CONFIG_PATH fragment mirroring the existing _HERMES_ENV_PATH, folded into _SENSITIVE_WRITE_TARGET (covers tee/>/>>/cp/mv) plus a dedicated sed -i / sed --in-place pattern for both config.yaml and .env.

This treats config.yaml as the security policy file (same category as auth.json / pairing/), warranting real two-surface pairing rather than a half-door.

No regression

Verified — only writes to the Hermes config/env files are newly gated:

  • Reads of ~/.hermes/config.yaml pass (not a write)
  • Normal writes (echo > /tmp/x.txt), normal sed -i on project files pass
  • Existing 193 approval + file_tools tests unchanged

Tests

  • tests/tools/test_file_tools.py::TestSensitivePathCheck (5, @Subway2023's) — write_file/patch deny
  • tests/tools/test_approval.py::TestHermesConfigWriteProtection (9, new) — terminal-side pairing incl. the sed -i gap and no-regression guards
  • Full suite slice: 202 passed

Closes #14639.

Co-authored-by: sbw2025 subw3@mail2.sysu.edu.cn

Infographic

config-write-protection-paired

Subway2023 and others added 3 commits June 1, 2026 03:12
Subway2023's #14639 blocks write_file/patch to ~/.hermes/config.yaml, but
the terminal side was only partially paired: echo>/tee/cp/mv to config.yaml
already tripped the project-config pattern, while `sed -i` and direct edits
slipped through with auto-approve. An unpaired write_file deny is theater per
SECURITY.md — the agent could flip approvals.mode=off via `sed -i` and the
mtime-keyed config cache reloads it mid-session.

config.yaml IS the security policy (approvals.mode/yolo/permanent allowlist
live there), so it warrants real pairing, not a half-door. Add a
_HERMES_CONFIG_PATH fragment mirroring _HERMES_ENV_PATH, fold it into
_SENSITIVE_WRITE_TARGET (covers tee/>/>>/cp/mv), and add sed -i coverage for
both config.yaml and .env. Pins 9 regression tests including no-regression
guards (reads pass, /tmp writes pass).

Co-authored-by: sbw2025 <subw3@mail2.sysu.edu.cn>
@alt-glitch alt-glitch added type/security Security vulnerability or hardening P2 Medium — degraded but workaround exists tool/file File tools (read, write, patch, search) tool/terminal Terminal execution and process management area/config Config system, migrations, profiles labels Jun 1, 2026
@teknium1
teknium1 merged commit ef3a650 into main Jun 1, 2026
21 of 22 checks passed
@teknium1
teknium1 deleted the fix/14639-pair-hermes-config-write-protection branch June 1, 2026 10:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles P2 Medium — degraded but workaround exists tool/file File tools (read, write, patch, search) tool/terminal Terminal execution and process management type/security Security vulnerability or hardening

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants