fix(file_tools): prevent agent from silently disabling exec approval via config write - #14639
Closed
Subway2023 wants to merge 1 commit into
Closed
fix(file_tools): prevent agent from silently disabling exec approval via config write#14639Subway2023 wants to merge 1 commit into
Subway2023 wants to merge 1 commit into
Conversation
…nt silent approval bypass
Collaborator
teknium1
added a commit
that referenced
this pull request
Jun 1, 2026
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>
teknium1
added a commit
that referenced
this pull request
Jun 1, 2026
3 tasks
SuperInstance
pushed a commit
to SuperInstance/hermes-construct
that referenced
this pull request
Jun 1, 2026
Subway2023's NousResearch#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>
teknium1
added a commit
that referenced
this pull request
Jun 1, 2026
…37046) * fix(file_tools): block agent writes to ~/.hermes/config.yaml to prevent silent approval bypass * fix(approval): pair terminal-side gate for ~/.hermes/config.yaml writes 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> * chore(release): map Subway2023 for PR #14639 salvage * fix(models): add gemini-3.5-flash to Gemini OAuth + API-key pickers #34581 swapped gemini-3-flash-preview -> gemini-3.5-flash in the OpenRouter and Nous lists but missed the curated Gemini catalogs, so the Google OAuth (google-gemini-cli) picker still offered the retired gemini-3-flash-preview slug and gemini-3.5-flash was unselectable. Per Google's docs gemini-3-flash-preview was renamed to gemini-3.5-flash and is served via Cloud Code Assist, so this completes the rename for: - google-gemini-cli (OAuth/Code Assist) picker - gemini (API-key) picker - gemini provider default_aux_model copilot keeps gemini-3-flash-preview (separate backend, own slug). --------- Co-authored-by: sbw2025 <subw3@mail2.sysu.edu.cn>
teknium1
added a commit
that referenced
this pull request
Jun 1, 2026
* fix(file_tools): block agent writes to ~/.hermes/config.yaml to prevent silent approval bypass * fix(approval): pair terminal-side gate for ~/.hermes/config.yaml writes 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> * chore(release): map Subway2023 for PR #14639 salvage * docs: expand quickstart Skills section The Skills section was two bare commands with no framing — it never said what a skill is, how skills load, or what the install slug means. Expanded to explain the concept, the bundled catalog, install/browse/use flow, and slash-command activation. Removed the inaccurate /skills chat-command hint (skills become individual /<name> commands; hermes skills is the CLI verb). --------- Co-authored-by: sbw2025 <subw3@mail2.sysu.edu.cn>
13 tasks
12 tasks
kossteg
pushed a commit
to kossteg/hermes-agent
that referenced
this pull request
Jun 16, 2026
kossteg
pushed a commit
to kossteg/hermes-agent
that referenced
this pull request
Jun 16, 2026
…ousResearch#37046) * fix(file_tools): block agent writes to ~/.hermes/config.yaml to prevent silent approval bypass * fix(approval): pair terminal-side gate for ~/.hermes/config.yaml writes Subway2023's NousResearch#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> * chore(release): map Subway2023 for PR NousResearch#14639 salvage * fix(models): add gemini-3.5-flash to Gemini OAuth + API-key pickers NousResearch#34581 swapped gemini-3-flash-preview -> gemini-3.5-flash in the OpenRouter and Nous lists but missed the curated Gemini catalogs, so the Google OAuth (google-gemini-cli) picker still offered the retired gemini-3-flash-preview slug and gemini-3.5-flash was unselectable. Per Google's docs gemini-3-flash-preview was renamed to gemini-3.5-flash and is served via Cloud Code Assist, so this completes the rename for: - google-gemini-cli (OAuth/Code Assist) picker - gemini (API-key) picker - gemini provider default_aux_model copilot keeps gemini-3-flash-preview (separate backend, own slug). --------- Co-authored-by: sbw2025 <subw3@mail2.sysu.edu.cn>
kossteg
pushed a commit
to kossteg/hermes-agent
that referenced
this pull request
Jun 16, 2026
* fix(file_tools): block agent writes to ~/.hermes/config.yaml to prevent silent approval bypass * fix(approval): pair terminal-side gate for ~/.hermes/config.yaml writes Subway2023's NousResearch#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> * chore(release): map Subway2023 for PR NousResearch#14639 salvage * docs: expand quickstart Skills section The Skills section was two bare commands with no framing — it never said what a skill is, how skills load, or what the install slug means. Expanded to explain the concept, the bundled catalog, install/browse/use flow, and slash-command activation. Removed the inaccurate /skills chat-command hint (skills become individual /<name> commands; hermes skills is the CLI verb). --------- Co-authored-by: sbw2025 <subw3@mail2.sysu.edu.cn>
kossteg
pushed a commit
to kossteg/hermes-agent
that referenced
this pull request
Jun 16, 2026
sed -i coverage for ~/.hermes/config.yaml and .env was added in NousResearch#14639, but perl -i and ruby -i — which perform the same direct file mutation — were not covered. The existing perl/ruby pattern only catches -e/-c (code evaluation), not -i (file mutation), so: perl -i -pe 's/approvals.mode: on/approvals.mode: off/' ~/.hermes/config.yaml bypasses the approval gate entirely, letting the agent flip approvals.mode off mid-session via the mtime-keyed config cache reload. Add a single pattern mirroring the sed -i lines: `\b(?:perl|ruby)\s+-[^\s]*i` against both _HERMES_CONFIG_PATH and _HERMES_ENV_PATH. Three regression tests pin the new coverage.
T02200059
pushed a commit
to T02200059/hermes-agent
that referenced
this pull request
Jun 18, 2026
Subway2023's NousResearch#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>
T02200059
pushed a commit
to T02200059/hermes-agent
that referenced
this pull request
Jun 18, 2026
T02200059
pushed a commit
to T02200059/hermes-agent
that referenced
this pull request
Jun 18, 2026
…ousResearch#37046) * fix(file_tools): block agent writes to ~/.hermes/config.yaml to prevent silent approval bypass * fix(approval): pair terminal-side gate for ~/.hermes/config.yaml writes Subway2023's NousResearch#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> * chore(release): map Subway2023 for PR NousResearch#14639 salvage * fix(models): add gemini-3.5-flash to Gemini OAuth + API-key pickers NousResearch#34581 swapped gemini-3-flash-preview -> gemini-3.5-flash in the OpenRouter and Nous lists but missed the curated Gemini catalogs, so the Google OAuth (google-gemini-cli) picker still offered the retired gemini-3-flash-preview slug and gemini-3.5-flash was unselectable. Per Google's docs gemini-3-flash-preview was renamed to gemini-3.5-flash and is served via Cloud Code Assist, so this completes the rename for: - google-gemini-cli (OAuth/Code Assist) picker - gemini (API-key) picker - gemini provider default_aux_model copilot keeps gemini-3-flash-preview (separate backend, own slug). --------- Co-authored-by: sbw2025 <subw3@mail2.sysu.edu.cn>
T02200059
pushed a commit
to T02200059/hermes-agent
that referenced
this pull request
Jun 18, 2026
* fix(file_tools): block agent writes to ~/.hermes/config.yaml to prevent silent approval bypass * fix(approval): pair terminal-side gate for ~/.hermes/config.yaml writes Subway2023's NousResearch#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> * chore(release): map Subway2023 for PR NousResearch#14639 salvage * docs: expand quickstart Skills section The Skills section was two bare commands with no framing — it never said what a skill is, how skills load, or what the install slug means. Expanded to explain the concept, the bundled catalog, install/browse/use flow, and slash-command activation. Removed the inaccurate /skills chat-command hint (skills become individual /<name> commands; hermes skills is the CLI verb). --------- Co-authored-by: sbw2025 <subw3@mail2.sysu.edu.cn>
T02200059
pushed a commit
to T02200059/hermes-agent
that referenced
this pull request
Jun 18, 2026
sed -i coverage for ~/.hermes/config.yaml and .env was added in NousResearch#14639, but perl -i and ruby -i — which perform the same direct file mutation — were not covered. The existing perl/ruby pattern only catches -e/-c (code evaluation), not -i (file mutation), so: perl -i -pe 's/approvals.mode: on/approvals.mode: off/' ~/.hermes/config.yaml bypasses the approval gate entirely, letting the agent flip approvals.mode off mid-session via the mtime-keyed config cache reload. Add a single pattern mirroring the sed -i lines: `\b(?:perl|ruby)\s+-[^\s]*i` against both _HERMES_CONFIG_PATH and _HERMES_ENV_PATH. Three regression tests pin the new coverage.
T02200059
pushed a commit
to T02200059/hermes-agent
that referenced
this pull request
Jun 18, 2026
…rc files tools/approval.py already denies tee/redirection writes to every _SENSITIVE_WRITE_TARGET (~/.ssh/*, ~/.netrc/.pgpass/.npmrc/.pypirc, shell rc files, ~/.hermes/config.yaml/.env) via the DANGEROUS_PATTERNS tee/`>` rules, but cp/mv/install were only paired for _SYSTEM_CONFIG_PATH (/etc) and the project-relative env/config target. So `cp evil ~/.ssh/authorized_keys` (SSH-key implant / persistence), `cp creds ~/.netrc`, and `cp evil ~/.bashrc` (login-time command injection) auto-approved while the equivalent tee/`>` forms were denied — an unpaired write deny is theater (same rationale as NousResearch#14639 / commit ee11882, which paired the terminal side for ~/.hermes/config.yaml writes but did not touch these cp/mv/install verbs on the broader sensitive set). Add one (cp|mv|install) DANGEROUS_PATTERNS entry reusing the existing _SENSITIVE_WRITE_TARGET fragment, anchored via _COMMAND_TAIL so it fires on the destination (last arg) only: reading OUT of a sensitive path (`cp ~/.ssh/config /tmp/x`) stays auto-approved. Description differs from the system-config cp entry so the two keep distinct approval keys (no silent cross-approval). Additive — does not subsume the /etc or project-config rules. Adds TestSensitiveCopyMovePattern: 5 positive cases (ssh authorized_keys, ssh private key via mv, netrc via install, bashrc, ~/.hermes/config.yaml) + 2 negative guards (copy FROM ssh, unrelated copy). The ssh/netrc/bashrc positives fail on main and pass on this branch; the negatives stay green both ways.
xyshanren
pushed a commit
to xyshanren/hermes-agent-cn
that referenced
this pull request
Jun 25, 2026
…ousResearch#37046) * fix(file_tools): block agent writes to ~/.hermes/config.yaml to prevent silent approval bypass * fix(approval): pair terminal-side gate for ~/.hermes/config.yaml writes Subway2023's NousResearch#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> * chore(release): map Subway2023 for PR NousResearch#14639 salvage * fix(models): add gemini-3.5-flash to Gemini OAuth + API-key pickers NousResearch#34581 swapped gemini-3-flash-preview -> gemini-3.5-flash in the OpenRouter and Nous lists but missed the curated Gemini catalogs, so the Google OAuth (google-gemini-cli) picker still offered the retired gemini-3-flash-preview slug and gemini-3.5-flash was unselectable. Per Google's docs gemini-3-flash-preview was renamed to gemini-3.5-flash and is served via Cloud Code Assist, so this completes the rename for: - google-gemini-cli (OAuth/Code Assist) picker - gemini (API-key) picker - gemini provider default_aux_model copilot keeps gemini-3-flash-preview (separate backend, own slug). --------- Co-authored-by: sbw2025 <subw3@mail2.sysu.edu.cn>
xyshanren
pushed a commit
to xyshanren/hermes-agent-cn
that referenced
this pull request
Jun 25, 2026
xyshanren
pushed a commit
to xyshanren/hermes-agent-cn
that referenced
this pull request
Jun 25, 2026
…rc files tools/approval.py already denies tee/redirection writes to every _SENSITIVE_WRITE_TARGET (~/.ssh/*, ~/.netrc/.pgpass/.npmrc/.pypirc, shell rc files, ~/.hermes/config.yaml/.env) via the DANGEROUS_PATTERNS tee/`>` rules, but cp/mv/install were only paired for _SYSTEM_CONFIG_PATH (/etc) and the project-relative env/config target. So `cp evil ~/.ssh/authorized_keys` (SSH-key implant / persistence), `cp creds ~/.netrc`, and `cp evil ~/.bashrc` (login-time command injection) auto-approved while the equivalent tee/`>` forms were denied — an unpaired write deny is theater (same rationale as NousResearch#14639 / commit 4e9d886, which paired the terminal side for ~/.hermes/config.yaml writes but did not touch these cp/mv/install verbs on the broader sensitive set). Add one (cp|mv|install) DANGEROUS_PATTERNS entry reusing the existing _SENSITIVE_WRITE_TARGET fragment, anchored via _COMMAND_TAIL so it fires on the destination (last arg) only: reading OUT of a sensitive path (`cp ~/.ssh/config /tmp/x`) stays auto-approved. Description differs from the system-config cp entry so the two keep distinct approval keys (no silent cross-approval). Additive — does not subsume the /etc or project-config rules. Adds TestSensitiveCopyMovePattern: 5 positive cases (ssh authorized_keys, ssh private key via mv, netrc via install, bashrc, ~/.hermes/config.yaml) + 2 negative guards (copy FROM ssh, unrelated copy). The ssh/netrc/bashrc positives fail on main and pass on this branch; the negatives stay green both ways.
xyshanren
pushed a commit
to xyshanren/hermes-agent-cn
that referenced
this pull request
Jun 25, 2026
sed -i coverage for ~/.hermes/config.yaml and .env was added in NousResearch#14639, but perl -i and ruby -i — which perform the same direct file mutation — were not covered. The existing perl/ruby pattern only catches -e/-c (code evaluation), not -i (file mutation), so: perl -i -pe 's/approvals.mode: on/approvals.mode: off/' ~/.hermes/config.yaml bypasses the approval gate entirely, letting the agent flip approvals.mode off mid-session via the mtime-keyed config cache reload. Add a single pattern mirroring the sed -i lines: `\b(?:perl|ruby)\s+-[^\s]*i` against both _HERMES_CONFIG_PATH and _HERMES_ENV_PATH. Three regression tests pin the new coverage.
xyshanren
pushed a commit
to xyshanren/hermes-agent-cn
that referenced
this pull request
Jun 25, 2026
Subway2023's NousResearch#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>
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(file_tools): prevent agent from silently disabling exec approval via config write
What does this PR do?
write_fileandpatchtools had no protection against writes to~/.hermes/config.yaml. A malicious or prompt-injected agent could exploit this to silently disable exec approval:read_file("~/.hermes/config.yaml")to read the current config.write_fileorpatchto setapprovals.mode: off.execute_codecalls bypasscheck_all_command_guards()entirely —approval_mode == "off"causes it to return{"approved": True}unconditionally.This PR adds
~/.hermes/config.yamlto the sensitive path protection in_check_sensitive_path(). Any attempt by an agent to write to the config file is rejected before reaching the filesystem, regardless of whether the path is expressed as an absolute path or via~.Related Issue
Fixes #
Type of Change
Changes Made
tools/file_tools.py: add_get_hermes_config_resolved()to lazily resolve and cache the canonical path of~/.hermes/config.yaml(viaget_config_path().resolve(), withexpanduserfallback)tools/file_tools.py: add a guard at the end of_check_sensitive_path()that rejects writes when the target path matches the Hermes config file — covers bothwrite_fileandpatchentry pointstests/tools/test_file_tools.py: addTestSensitivePathCheckwith 5 cases covering the new protection and verifying no regression on normal file writes or existing system-path blocksHow to Test
pytest tests/tools/test_file_tools.py::TestSensitivePathCheck -v— all 5 cases should pass.pytest tests/tools/test_file_tools.py -q— all 28 tests should pass.approvals:\n mode: offto~/.hermes/config.yaml— confirm it receives an error response containing "Refusing to write to Hermes config file".Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AScreenshots / Logs