fix(plugin-dev): hook JSON to stdout, tighten su* glob, fix CI detection and JSON injection in examples#68785
Open
AZERDSQ131 wants to merge 1 commit into
Conversation
…n su* glob; fix -f/-d check and JSON injection in example hooks - validate-bash.sh: remove >&2 from all three decision echoes — Claude Code reads hook JSON responses from stdout, not stderr; writing to stderr means the permissionDecision and systemMessage are silently discarded - validate-bash.sh: replace `su*` glob (which matches submodule, subl, sum…) with `^su([[:space:]]|-|$)` regex so only the `su` switch-user command and its flags are caught, not every command starting with "su" - validate-write.sh: same stdout fix for all three decision echoes - validate-write.sh: replace shell string-concatenation into JSON literals with `jq -n --arg` so paths containing `"` or `\` produce valid JSON instead of breaking the message structure - load-context.sh: `.github/workflows` is a directory; `-f` always returns false for it — change to `-d` so GitHub Actions CI is correctly detected Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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.
Problems
Three example hook scripts in
plugins/plugin-dev/skills/hook-development/examples/have bugs that make them incorrect as reference implementations.BUG-25 —
validate-bash.sh: hook responses written to stderrLines 26, 32, 38 use
>&2on the decision JSON:Claude Code reads structured hook responses (
permissionDecision,systemMessage) from stdout. Writing to stderr means the JSON is never processed — the hook exits 2 and the operation is blocked, but Claude receives no explanation and the UI shows nothing.Fix: remove
>&2from all three decision echoes.BUG-25b —
validate-bash.sh:su*glob matches any command starting with "su"Line 37:
su*is a glob that matchessubmodule,subl,sum,substring,sudo(already caught), etc.git submodule statuswould trigger the privilege-escalation block.Fix: replace with
[[ "$command" =~ ^su([[:space:]]|-|$) ]]— matches baresu,su -l user,su root, but notsubmodule.BUG-26 —
validate-write.sh: same stderr bug + JSON injection via$file_pathAll three decision echoes write to stderr (same root cause as BUG-25).
Additionally,
$file_pathis embedded in the JSON string via shell concatenation:If
$file_pathcontains"or\(e.g.C:\Users\foo\..\"secret"), the resulting JSON is syntactically invalid and Claude Code cannot parse the hook response.Fix: use
jq -n --arg p "$file_path" '... + $p'—jqproperly escapes any character.BUG-27 —
load-context.sh:-fused to test a directoryLine 50:
.github/workflowsis a directory.-ftests for regular files and always returns false for directories — GitHub Actions CI is never detected andHAS_CIis never set.Fix: change
-fto-d.Changes
examples/validate-bash.sh>&2; changesu*glob to regexexamples/validate-write.sh>&2; usejq -n --argfor safe JSONexamples/load-context.sh-fto-dfor.github/workflowsTesting
validate-bash.sh: runecho '{"tool_name":"Bash","tool_input":{"command":"rm -rf /tmp/x"}}' | bash validate-bash.sh— output JSON now appears on stdoutvalidate-bash.sh:echo '{"tool_name":"Bash","tool_input":{"command":"git submodule status"}}' | bash validate-bash.sh— exits 0 (not blocked)validate-write.sh:echo '{"tool_input":{"file_path":"foo\"bar"}}' ... | bash validate-write.sh— produces valid JSONload-context.sh: run in a repo with.github/workflows/—HAS_CInow set