mirror of
https://github.com/trailofbits/claude-code-config
synced 2026-06-21 14:11:43 +00:00
fix: expand deny rules and harden hook regex for rm and pipe-to-shell bypasses
Deny rules previously only blocked `rm -rf` and `rm -fr` (lowercase, combined flags only). All other flag forms bypassed both security layers silently. Expand deny rules to cover: - All case combinations of combined short flags: -Rf, -rF, -RF, -fR, -Fr, -FR - All orderings of separated short flags: -r -f, -r -F, -R -f, -R -F and their reverses (-f -r, -f -R, -F -r, -F -R) - GNU long-form flags: --recursive, --recursive --force, --force --recursive - Pipe-to-shell via sh and zsh: * | sh, * | zsh - Process substitution: bash <(curl *) - Spaced pipe variant for existing rules: curl *| bash*, wget *| bash* Harden PreToolUse hook regex: - Old regex required combined lowercase flags only (-rf / -fr pattern) - New regex uses three chained case-insensitive grep checks: 1. Confirm rm is the actual command (not a substring of another word or arg) 2. Detect any recursive flag (-r, -R, -[flags]r, --recursive) 3. Detect any force flag (-f, -F, -[flags]f, --force) - Handles commands chained with ; && || | - Verified against 25 test cases (19 must-block, 6 must-allow)
This commit is contained in:
+24
-2
@@ -13,11 +13,33 @@
|
||||
"deny": [
|
||||
"Bash(rm -rf *)",
|
||||
"Bash(rm -fr *)",
|
||||
"Bash(rm -Rf *)",
|
||||
"Bash(rm -rF *)",
|
||||
"Bash(rm -RF *)",
|
||||
"Bash(rm -fR *)",
|
||||
"Bash(rm -Fr *)",
|
||||
"Bash(rm -FR *)",
|
||||
"Bash(rm -r -f *)",
|
||||
"Bash(rm -r -F *)",
|
||||
"Bash(rm -R -f *)",
|
||||
"Bash(rm -R -F *)",
|
||||
"Bash(rm -f -r *)",
|
||||
"Bash(rm -f -R *)",
|
||||
"Bash(rm -F -r *)",
|
||||
"Bash(rm -F -R *)",
|
||||
"Bash(rm --recursive *)",
|
||||
"Bash(rm --recursive --force *)",
|
||||
"Bash(rm --force --recursive *)",
|
||||
"Bash(sudo *)",
|
||||
"Bash(mkfs *)",
|
||||
"Bash(dd *)",
|
||||
"Bash(curl *|bash*)",
|
||||
"Bash(curl *| bash*)",
|
||||
"Bash(wget *|bash*)",
|
||||
"Bash(wget *| bash*)",
|
||||
"Bash(* | sh)",
|
||||
"Bash(* | zsh)",
|
||||
"Bash(bash <(curl *))",
|
||||
"Bash(git push --force*)",
|
||||
"Bash(git push *--force*)",
|
||||
"Bash(git reset --hard*)",
|
||||
@@ -53,11 +75,11 @@
|
||||
"hooks": [
|
||||
{
|
||||
"type": "command",
|
||||
"command": "CMD=$(jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qE 'rm[[:space:]]+-[^[:space:]]*r[^[:space:]]*f'; then echo 'BLOCKED: Use trash instead of rm -rf' >&2; exit 2; fi"
|
||||
"command": "CMD=$(jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qiE '(^|;[[:space:]]*|&&[[:space:]]*|[|][|][[:space:]]*|[|][[:space:]]*)rm[[:space:]]' && echo \"$CMD\" | grep -qiE '(^|[[:space:]])-[a-zA-Z]*[rR]|--recursive' && echo \"$CMD\" | grep -qiE '(^|[[:space:]])-[a-zA-Z]*[fF]|--force'; then echo 'BLOCKED: Use trash instead of rm -rf' >&2; exit 2; fi"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"command": "CMD=$(jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qE 'git[[:space:]]+push.*(main|master)'; then echo 'BLOCKED: Use feature branches, not direct push to main' >&2; exit 2; fi"
|
||||
"command": "CMD=$(jq -r '.tool_input.command'); if echo \"$CMD\" | grep -qiE 'git[[:space:]]+push.*(main|master)'; then echo 'BLOCKED: Use feature branches, not direct push to main' >&2; exit 2; fi"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user