Skip to content

Commit 1cf02a6

Browse files
sjnimsclaude
andauthored
fix(security): prevent command injection in test-hook.sh (#148)
## Description Fix command injection vulnerability in `test-hook.sh` by using proper argument passing instead of string interpolation in bash -c. The previous implementation was vulnerable: ```bash # Vulnerable (before) output=$(timeout "$TIMEOUT" bash -c "cat '$TEST_INPUT' | $HOOK_SCRIPT" 2>&1) ``` This has been fixed with: 1. **Path validation**: Reject hook script paths containing dangerous shell characters (`;|&`$(){}<>`) 2. **Safe argument passing**: Use bash -c's positional parameters via `--` separator: ```bash # Safe (after) if [ "$HOOK_IS_EXECUTABLE" = true ]; then output=$(timeout "$TIMEOUT" bash -c 'cat "$1" | "$2"' -- "$TEST_INPUT" "$HOOK_SCRIPT" 2>&1) else output=$(timeout "$TIMEOUT" bash -c 'cat "$1" | bash "$2"' -- "$TEST_INPUT" "$HOOK_SCRIPT" 2>&1) fi ``` ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update (improvements to README, CLAUDE.md, or component docs) - [ ] Refactoring (code change that neither fixes a bug nor adds a feature) - [ ] Configuration change (changes to .markdownlint.json, plugin.json, etc.) ## Component(s) Affected - [ ] Commands (`/plugin-dev:*`) - [x] Skills (methodology and best practices) - [ ] Agents (requirements-assistant) - [ ] Hooks (UserPromptSubmit) - [ ] Documentation (README.md, CLAUDE.md, SECURITY.md) - [ ] Configuration (.markdownlint.json, plugin.json, marketplace.json) - [ ] Issue/PR templates - [ ] Other (please specify): ## Motivation and Context The `test-hook.sh` script used string interpolation when passing arguments to `bash -c`, which could allow command injection through maliciously crafted file paths. This security fix ensures that file paths are properly validated and passed as positional parameters. ## How Has This Been Tested? **Test Configuration**: - Claude Code version: Latest - GitHub CLI version: 2.x - OS: macOS - Testing repository: N/A **Test Steps**: 1. Load plugin with `cc --plugin-dir plugins/plugin-dev` 2. Run `./skills/hook-development/scripts/test-hook.sh` with a normal hook script 3. Verify normal execution still works 4. Verify paths with spaces work correctly 5. Verify paths with dangerous characters (`;|&`) are rejected with error message ## Checklist ### General - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas (if applicable) - [x] My changes generate no new warnings or errors ### Documentation - [ ] I have updated the documentation accordingly (README.md, CLAUDE.md, or component docs) - [ ] I have updated YAML frontmatter (if applicable) - [ ] I have verified all links work correctly ### Markdown - [x] I have run `markdownlint` and fixed all issues - [x] My markdown follows the repository style (ATX headers, dash lists, fenced code blocks) - [ ] I have verified special HTML elements are properly closed (`<example>`, `<commentary>`, etc.) ### Component-Specific Checks N/A - This is a shell script security fix, not a command/skill/agent change. ### Testing - [ ] I have tested the plugin locally with `cc --plugin-dir plugins/plugin-dev` - [ ] I have tested the full workflow (if applicable) - [ ] I have verified GitHub CLI integration works (if applicable) - [ ] I have tested in a clean repository (not my development repo) ### Version Management (if applicable) - [ ] I have updated version numbers in both `plugin.json` and `marketplace.json` (if this is a release) - [ ] I have updated CHANGELOG.md with relevant changes ## Screenshots (if applicable) N/A ## Additional Notes This is a security fix identified during code review. The vulnerability could theoretically be exploited if an attacker could control the hook script path passed to `test-hook.sh`. ## Reviewer Notes **Areas that need special attention**: - Verify the path validation regex correctly catches all dangerous shell characters - Verify the positional parameter approach works correctly for both executable and non-executable scripts **Known limitations or trade-offs**: - The path validation is conservative and may reject some technically-safe paths that contain these characters --- 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 1af7555 commit 1cf02a6

1 file changed

Lines changed: 26 additions & 2 deletions

File tree

  • plugins/plugin-dev/skills/hook-development/scripts

plugins/plugin-dev/skills/hook-development/scripts/test-hook.sh

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,34 @@ if [ ! -f "$HOOK_SCRIPT" ]; then
141141
exit 1
142142
fi
143143

144+
# Security: Validate hook script path doesn't contain dangerous characters
145+
# This prevents potential command injection through maliciously crafted paths
146+
if [[ "$HOOK_SCRIPT" =~ [\;\|\&\`\$\(\)\{\}\<\>] ]]; then
147+
echo "❌ Error: Hook script path contains invalid characters"
148+
echo " Path must not contain: ; | & \` \$ ( ) { } < >"
149+
exit 1
150+
fi
151+
152+
# Track if we need to invoke with bash explicitly
153+
HOOK_IS_EXECUTABLE=true
144154
if [ ! -x "$HOOK_SCRIPT" ]; then
145155
echo "⚠️ Warning: Hook script is not executable. Attempting to run with bash..."
146-
HOOK_SCRIPT="bash $HOOK_SCRIPT"
156+
HOOK_IS_EXECUTABLE=false
147157
fi
148158

149159
if [ ! -f "$TEST_INPUT" ]; then
150160
echo "❌ Error: Test input not found: $TEST_INPUT"
151161
exit 1
152162
fi
153163

164+
# Security: Validate test input path doesn't contain dangerous characters
165+
# This mirrors the HOOK_SCRIPT validation for defense-in-depth
166+
if [[ "$TEST_INPUT" =~ [\;\|\&\`\$\(\)\{\}\<\>] ]]; then
167+
echo "❌ Error: Test input path contains invalid characters"
168+
echo " Path must not contain: ; | & \` \$ ( ) { } < >"
169+
exit 1
170+
fi
171+
154172
# Validate test input JSON
155173
if ! jq empty "$TEST_INPUT" 2>/dev/null; then
156174
echo "❌ Error: Test input is not valid JSON"
@@ -187,7 +205,13 @@ echo ""
187205
start_time=$(date +%s)
188206

189207
set +e
190-
output=$(timeout "$TIMEOUT" bash -c "cat '$TEST_INPUT' | $HOOK_SCRIPT" 2>&1)
208+
# Use proper argument passing to prevent command injection
209+
# Arguments are passed safely via bash -c's positional parameters
210+
if [ "$HOOK_IS_EXECUTABLE" = true ]; then
211+
output=$(timeout "$TIMEOUT" bash -c 'cat "$1" | "$2"' -- "$TEST_INPUT" "$HOOK_SCRIPT" 2>&1)
212+
else
213+
output=$(timeout "$TIMEOUT" bash -c 'cat "$1" | bash "$2"' -- "$TEST_INPUT" "$HOOK_SCRIPT" 2>&1)
214+
fi
191215
exit_code=$?
192216
set -e
193217

0 commit comments

Comments
 (0)