Skip to content

security: close three dangerous-command detection gaps (inspired by Claude Code 2.1.113)#11861

Closed
teknium1 wants to merge 1 commit into
mainfrom
claude-code-inspired/dangerous-cmd-hardening
Closed

security: close three dangerous-command detection gaps (inspired by Claude Code 2.1.113)#11861
teknium1 wants to merge 1 commit into
mainfrom
claude-code-inspired/dangerous-cmd-hardening

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Tightens detect_dangerous_command() against three bash-approval bypasses that Claude Code shipped patches for in v2.1.113 (April 17 2026). All three were confirmed as real gaps on current main via E2E.

Gaps closed

Gap Example that previously slipped through Now caught by
macOS /private/{etc,var,tmp,home} paths echo 'root ALL=NOPASSWD: ALL' > /private/etc/sudoers _SYSTEM_CONFIG_PATH fragment (redirect / tee / cp / mv / install / sed -i)
killall with SIGKILL or regex killall -KILL firefox, killall -r 'fire.*' 3 new \bkillall\s+... patterns
find -execdir rm find . -execdir rm {} \; existing find-exec pattern extended to -exec(?:dir)?

On macOS, /etc, /var, /tmp, /home are symlinks to /private/{etc,var,tmp,home}. A write to /private/etc/sudoers works identically to /etc/sudoers but bypassed the plain /etc/ pattern check.

Design

Extracted a shared _SYSTEM_CONFIG_PATH regex fragment so /etc/ and its /private/ mirror stay in sync across all 6 patterns that write into system-config paths. Adding another system-protected path in the future is a one-line edit to that fragment.

Validation

Before After
New Claude Code 2.1.113 cases caught 0/19 19/19
Existing dangerous patterns (regression) 30/30 30/30
Benign commands (false-positive guard) 23/23 23/23
test_approval.py suite 117 passed 149 passed

32 new test cases in 4 test classes guard the fix:

  • TestMacOSPrivateSystemPaths (11 cases)
  • TestKillallKillSignals (9 cases — including killall -l / -V false-positive guards)
  • TestFindExecdir (4 cases — including find -execdir ls false-positive guard)
  • TestEtcPatternsUnaffectedByRefactor (6 regression guards on the existing /etc/ coverage after the _SYSTEM_CONFIG_PATH refactor)

Pre-existing test_approval_heartbeat.py failures confirmed unrelated (reproduce on main without this change — thread-timing flake).

Source material

Adaptation notes

  • Wrapper bypasses (env rm -rf, sudo rm -rf, setsid rm -rf) were already caught by hermes because \brm\b still matches mid-command — verified E2E across env, sudo, watch, ionice, setsid, nice, timeout, time, stdbuf. No change needed there.
  • Did not port Claude Code's /less-permission-prompts slash command in this PR — separate scope.

Port three hardening patches from Claude Code 2.1.113's expanded deny
rules to hermes' detect_dangerous_command() pattern list.

1. macOS /private/{etc,var,tmp,home} system paths
   /etc, /var, /tmp, /home are symlinks to /private/<name> on macOS.
   A write to /private/etc/sudoers works identically to /etc/sudoers
   but bypassed the plain /etc/ pattern check. Extracted a shared
   _SYSTEM_CONFIG_PATH fragment so /etc/ and the /private/ mirror
   stay in sync across redirect / tee / cp / mv / install / sed -i
   patterns.

2. killall -9 / -KILL / -SIGKILL / -s KILL / -r <regex>
   Parallel to the existing pkill -9 pattern. killall -9 against
   non-hermes processes was previously unprotected, and killall -r
   can sweep unrelated processes matching a regex.

3. find -execdir rm
   Same destructive effect as find -exec rm but ran in each match's
   directory. The previous pattern required a literal '-exec ' so
   -execdir slipped through.

Guarded by 32 new test cases in 4 test classes:
  - TestMacOSPrivateSystemPaths  (11 cases)
  - TestKillallKillSignals       (9 cases)
  - TestFindExecdir              (4 cases)
  - TestEtcPatternsUnaffectedByRefactor  (6 regression guards on
    the existing /etc/ coverage after the _SYSTEM_CONFIG_PATH refactor)

Inspiration: https://github.com/anthropics/claude-code/releases
(Claude Code 2.1.113, April 17 2026 - "Enhanced deny rules" and
"Dangerous path protection")
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Supply Chain Risk Detected

This PR contains patterns commonly associated with supply chain attacks. This does not mean the PR is malicious — but these patterns require careful human review before merging.

⚠️ WARNING: exec() or eval() usage

Dynamic code execution can hide malicious behavior, especially when combined with base64 or network fetches.

Matches (first 20):

265:+    (r'\bfind\b.*-exec(?:dir)?\s+(/\S*/)?rm\b', "find -exec/-execdir rm"),

Automated scan triggered by supply-chain-audit. If this is a false positive, a maintainer can approve after manual review.

@trevorgordon981

Copy link
Copy Markdown

Review of PR #11861: Security - Close Dangerous Command Detection Gaps

Summary

This PR adds critical security test coverage inspired by Claude Code 2.1.113, closing two important gaps in dangerous command detection:

  1. macOS Private Path Protection: Guards against commands that write to /private/{etc,var,tmp} paths, which are symlinks to the actual system config locations on macOS
  2. killall Signal Protection: Extends detection to catch killall -9, killall -KILL, killall -s KILL, and regex-based process killing that could wipe out unrelated processes

Key Additions

1. TestMacOSPrivateSystemPaths (12 new tests)

Tests the _SYSTEM_CONFIG_PATH fragment used across multiple command patterns:

  • ✅ Redirect operations: echo > /private/etc/ssudoers
  • ✅ Tee operations: echo | tee /private/etc/hosts
  • ✅ Copy operations: cp /private/etc/...
  • ✅ Move operations: mv /private/etc/...
  • ✅ Install operations: install /private/etc/...
  • ✅ In-place sed: sed -i /private/etc/...
  • ✅ Long flag sed: sed --in-place /private/var/...
  • ✅ Safe operations verified: ls /private, echo 'mentioning /private'

2. TestKillallKillSignals (multiple new tests)

Extends beyond the existing pkill -9 detection to catch:

  • killall -9
  • killall -KILL
  • killall -s KILL
  • killall -r <regex> (broad process sweeps)

Security Impact

Prevents bypass attacks: Commands that previously slipped through detection are now caught
macOS-specific protection: Addresses the unique /private/* symlink structure on macOS
Comprehensive coverage: Tests both dangerous and safe operations to avoid false positives
Inspired by industry best practices: Based on Claude Code 2.1.113 security improvements

Code Quality

✅ Well-structured test classes with clear documentation
✅ Comprehensive test coverage (20+ new tests)
✅ Clear before/after examples in docstrings
✅ Proper distinction between dangerous and safe operations
✅ Addresses real security gaps, not theoretical concerns

Recommendation

LGTM - Critical security improvement 🚀

This PR closes important security gaps that could be exploited to modify system configurations or kill arbitrary processes. The tests are well-written, comprehensive, and based on real-world security improvements from Claude Code.

No additional changes needed - ready to merge!

@alt-glitch alt-glitch added type/security Security vulnerability or hardening P1 High — major feature broken, no workaround comp/tools Tool registry, model_tools, toolsets tool/terminal Terminal execution and process management labels Apr 24, 2026
@teknium1

Copy link
Copy Markdown
Contributor Author

Closing in favor of #26829, which salvages this PR onto current main. All three bypasses confirmed reproducible on main before fix; all 12 E2E bypass tests now blocked; all 8 benign-command tests still pass. Conflicts resolved keeping main's _PROJECT_ENV_PATH / project-env additions alongside the new _SYSTEM_CONFIG_PATH fragment + killall / find-execdir rules.

@teknium1 teknium1 closed this May 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/tools Tool registry, model_tools, toolsets P1 High — major feature broken, no workaround 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.

4 participants