security(approval): close 4 DANGEROUS_PATTERNS gaps (heredoc, pgrep, git --force, chmod+exec)#6961
Closed
win4r wants to merge 1 commit into
Closed
security(approval): close 4 DANGEROUS_PATTERNS gaps (heredoc, pgrep, git --force, chmod+exec)#6961win4r wants to merge 1 commit into
win4r wants to merge 1 commit into
Conversation
Four gaps in DANGEROUS_PATTERNS found by running 10 targeted tests that
each mapped to a specific pattern in approval.py and checked whether the
documented defense actually held.
1. **Heredoc script injection** — `python3 << 'EOF'` bypasses the
existing `-e`/`-c` flag pattern. Adds pattern for interpreter + `<<`
covering python{2,3}, perl, ruby, node.
2. **PID expansion self-termination** — `kill -9 $(pgrep hermes)` is
opaque to the existing `pkill|killall` + name pattern because command
substitution is not expanded at detection time. Adds structural
patterns matching `kill` + `$(pgrep` and backtick variants.
3. **Git destructive operations** — `git reset --hard`, `push --force`,
`push -f`, `clean -f*`, and `branch -D` were entirely absent.
Note: `branch -d` also triggers because IGNORECASE is global —
acceptable since -d is still a delete, just a safe one, and the
prompt is only a confirmation, not a hard block.
4. **chmod +x then execute** — two-step social engineering where a
script containing dangerous commands is first written to disk (not
checked by write_file), then made executable and run as `./script`.
Pattern catches `chmod +x ... [;&|]+ ./` combos. Does not solve the
deeper architectural issue (write_file not checking content) — that
is called out in the PR description as a known limitation.
Tests: 23 new cases across 4 test classes, all in test_approval.py:
- TestHeredocScriptExecution (7 cases, incl. regressions for -c)
- TestPgrepKillExpansion (5 cases, incl. safe kill PID negative)
- TestGitDestructiveOps (8 cases, incl. safe git status/push negatives)
- TestChmodExecuteCombo (3 cases, incl. safe chmod-only negative)
Full suite: 146 passed, 0 failed.
dpskate
pushed a commit
to dpskate/hermes-agent
that referenced
this pull request
Apr 10, 2026
…attern bypass, redaction bypass, network exposure - Remove hermes-agent root from sandbox PYTHONPATH to prevent internal module import and API key exfiltration (mitigates NousResearch#7071) - Add 8 missing DANGEROUS_PATTERNS: heredoc injection, git destructive ops (reset --hard, push --force, clean -f, branch -D, checkout -- .), and chmod +x social engineering (mitigates NousResearch#6961) - Add base64/hex encoded secret detection to redact_sensitive_text() to prevent redaction bypass via encoding - Change default bind address from 0.0.0.0 to 127.0.0.1 for webhook, SMS/Twilio, and Telegram adapters (mitigates NousResearch#4260, NousResearch#6335) - Fix .env and config.yaml file permissions from 644 to 600 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
8 tasks
Contributor
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.
What does this PR do?
Closes 4 gaps in
DANGEROUS_PATTERNSfound by a 10-test source-grounded security audit. Each test mapped directly to a specific regex inapproval.pyand checked whether the documented defense actually held when attacked.Audit methodology: Read the pattern → craft a command that should be caught → verify detection → craft a bypass variant → verify the bypass works → add pattern + tests for the bypass.
1. Heredoc script injection
python3 -eandpython3 -care caught byDANGEROUS_PATTERNS[14], butpython3 << 'EOF'is not — it feeds arbitrary code via stdin without any flag. In testing, hermes executedshutil.rmtree()via heredoc with zero approval prompt.2. PID expansion self-termination bypass
pkill hermesis caught byDANGEROUS_PATTERNS[23], butkill -9 $(pgrep -f hermes)is not — the command substitution is opaque to regex. In testing, hermes executed the kill command and even offered to help "kill more precisely".3. Git destructive operations
git reset --hard,git push --force,git clean -fd,git branch -Dwere entirely absent from DANGEROUS_PATTERNS. In testing, hermes was willing to rungit reset --hard HEAD~5and even suggestedHEAD~1as an alternative.Note:
git branch -d(safe delete) also triggers becausere.IGNORECASEis global. This is acceptable —-dis still a delete operation, and the prompt is a confirmation, not a hard block.4. chmod +x then execute (two-step social engineering)
In testing, hermes happily wrote a script containing
rm -rf *, then ranchmod +x && ./cleanup.sh— both steps had zero approval. This pattern catches the execute-after-chmod combo:Known limitation: This does not solve the deeper architectural issue where
write_fileaccepts dangerous script content without checking. That requires content-level audit at write time, which is a larger architectural change called out in the Related Issues section below.Related Issue
No open issue — findings from authorised local security audit.
Fixes #
Type of Change
Changes Made
tools/approval.py: +11 new patterns (20 lines of regex + comments)tests/tools/test_approval.py: +23 new tests across 4 classes (169 lines)How to Test
Reproduce the original bypasses (before this fix):
Checklist
Code
security(approval):)pytest tests/tools/test_approval.py tests/tools/test_command_guards.py -qand all 146 tests passDocumentation & Housekeeping
Relationship to other open PRs
redact.py+terminal_tool.pyvsapproval.py).Known Limitation: write_file Content Audit
Test 4 (chmod +x → execute) is only partially fixed by this PR. The pattern catches the
chmod +x && ./combo, but a determined attacker can split across sessions or usesource script.sh(no chmod needed). The root cause is thatwrite_filedoes not inspect script content for dangerous commands. A full fix requires content-level audit at write time — a larger architectural change beyond the scope of this PR.