Skip to content

Commit cd367ee

Browse files
committed
Reject shell metacharacters in cancel allowlist exception
The methodology-phase cancel exception returned early for any command beginning with cancel-rlcr-loop.sh that did not contain `;`, `|`, or `&`. Payloads such as cancel-rlcr-loop.sh $(touch /tmp/pwn) cancel-rlcr-loop.sh \`touch /tmp/pwn\` cancel-rlcr-loop.sh > /tmp/pwn cancel-rlcr-loop.sh\nrm -rf / still satisfied the narrow metachar check and short-circuited past the downstream file-mod, redirection, and interpreter blockers, effectively letting arbitrary write operations ride alongside the cancel invocation. Extend the reject list to include command substitution opener `$(`, backticks, redirection (`<`, `>`), and embedded newlines, and switch from `echo | grep` to a bash case expression so a newline inside the command text does not bypass the single-line grep semantics. Preserve `${CLAUDE_PLUGIN_ROOT}` variable expansion (which does not use `$(`) so the slash-command cancel path continues to work.
1 parent 0ca864d commit cd367ee

1 file changed

Lines changed: 17 additions & 4 deletions

File tree

hooks/loop-bash-validator.sh

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,23 @@ if [[ -n "$_MA_BASH_DIR" ]] && [[ -f "$_MA_BASH_DIR/methodology-analysis-state.m
8484
# token with no embedded whitespace, otherwise commands like
8585
# `bash cancel-rlcr-loop.sh` or `tee cancel-rlcr-loop.sh` would match.
8686
# The script name must be followed by whitespace or end-of-line so trailing
87-
# tokens cannot hide additional arguments. Reject if chained with shell
88-
# operators.
89-
if echo "$COMMAND_LOWER" | grep -qE '^[[:space:]]*"?([^[:space:]"]+/)?cancel-rlcr-loop\.sh"?([[:space:]]|$)' && \
90-
! echo "$COMMAND_LOWER" | grep -qE '[;|&]'; then
87+
# tokens cannot hide additional arguments.
88+
#
89+
# Also reject any shell metacharacter that can inject or redirect work
90+
# after the cancel invocation: pipes/sequence/background operators,
91+
# command substitution ($(...) or backticks), redirection (<, >), and
92+
# multi-line payloads. The earlier narrower check only rejected ; | &,
93+
# letting payloads like `cancel-rlcr-loop.sh $(touch /tmp/pwn)` or a
94+
# newline-delimited second command slip past this early exit and reach
95+
# arbitrary file modifications before the downstream blockers run.
96+
_ma_has_shell_meta=false
97+
case "$COMMAND_LOWER" in
98+
*';'*|*'|'*|*'&'*|*'`'*|*'>'*|*'<'*|*'$('*|*$'\n'*)
99+
_ma_has_shell_meta=true
100+
;;
101+
esac
102+
if [[ "$_ma_has_shell_meta" != "true" ]] && \
103+
echo "$COMMAND_LOWER" | grep -qE '^[[:space:]]*"?([^[:space:]"]+/)?cancel-rlcr-loop\.sh"?([[:space:]]|$)'; then
91104
exit 0
92105
fi
93106
# Block git commands that modify the working tree

0 commit comments

Comments
 (0)