Skip to content

Commit 58b6f73

Browse files
committed
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)
1 parent df8374d commit 58b6f73

1 file changed

Lines changed: 24 additions & 2 deletions

File tree

settings.json

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,33 @@
1313
"deny": [
1414
"Bash(rm -rf *)",
1515
"Bash(rm -fr *)",
16+
"Bash(rm -Rf *)",
17+
"Bash(rm -rF *)",
18+
"Bash(rm -RF *)",
19+
"Bash(rm -fR *)",
20+
"Bash(rm -Fr *)",
21+
"Bash(rm -FR *)",
22+
"Bash(rm -r -f *)",
23+
"Bash(rm -r -F *)",
24+
"Bash(rm -R -f *)",
25+
"Bash(rm -R -F *)",
26+
"Bash(rm -f -r *)",
27+
"Bash(rm -f -R *)",
28+
"Bash(rm -F -r *)",
29+
"Bash(rm -F -R *)",
30+
"Bash(rm --recursive *)",
31+
"Bash(rm --recursive --force *)",
32+
"Bash(rm --force --recursive *)",
1633
"Bash(sudo *)",
1734
"Bash(mkfs *)",
1835
"Bash(dd *)",
1936
"Bash(curl *|bash*)",
37+
"Bash(curl *| bash*)",
2038
"Bash(wget *|bash*)",
39+
"Bash(wget *| bash*)",
40+
"Bash(* | sh)",
41+
"Bash(* | zsh)",
42+
"Bash(bash <(curl *))",
2143
"Bash(git push --force*)",
2244
"Bash(git push *--force*)",
2345
"Bash(git reset --hard*)",
@@ -53,11 +75,11 @@
5375
"hooks": [
5476
{
5577
"type": "command",
56-
"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"
78+
"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"
5779
},
5880
{
5981
"type": "command",
60-
"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"
82+
"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"
6183
}
6284
]
6385
}

0 commit comments

Comments
 (0)