Security: rtk-rewrite.sh missing -- terminator on rtk rewrite "$CMD" (line 55) enables flag-injection #1350
Description
Summary
In hooks/rtk-rewrite.sh (v3, line 55), the call REWRITTEN=$(rtk rewrite "$CMD" 2>/dev/null) does not use -- to signal end-of-options. If $CMD starts with - (e.g. a pathological LLM-generated command like --help), rtk rewrite interprets the command as its own CLI flag, emits help text with exit 0, and the hook feeds that help text back to Claude Code as the rewritten tool_input.command.
Claude Code's Bash tool then shell-executes the help text. The help text contains $(rtk rewrite "$CMD") in an example snippet, which bash will expand during execution.
Reproduction (rtk v0.36.0 on Linux x86_64 musl)
$ rtk --version
rtk 0.36.0
$ echo '{"tool_input":{"command":"--help"}}' | bash ~/.claude/hooks/rtk-rewrite.sh
{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow","permissionDecisionReason":"RTK auto-rewrite","updatedInput":{"command":"Rewrite a raw command to its RTK equivalent (single source of truth for hooks)\n\n[...]\n\nUsed by Claude Code, Gemini CLI, and other LLM hooks: REWRITTEN=$(rtk rewrite \"$CMD\") || exit 0\n\n[...]"}}}
The updatedInput.command is now the help text — which CC's Bash tool will attempt to execute.
Impact
Severity: High (practical triggerability is low — Claude rarely emits ---prefixed commands — but the exploit path exists: any LLM-generated command starting with -/-- is transformed into arbitrary shell-interpretable text).
Fix
One-line change in hooks/rtk-rewrite.sh:
-REWRITTEN=$(rtk rewrite "$CMD" 2>/dev/null)
+REWRITTEN=$(rtk rewrite -- "$CMD" 2>/dev/null)Also consider:
- Verify
rtk rewriteaccepts--as end-of-options marker (if not, add that to the CLI parser). - Add a defensive check in the hook that refuses to auto-allow when
$REWRITTENis empty or starts with non-command-looking text (e.g. looks like help output / contains newlines).
Workaround (users can apply today)
Wrap the hook command in settings.json with a case-guard that refuses any command starting with -:
"command": "INPUT=$(cat); CMD=$(echo \"$INPUT\" | jq -r '.tool_input.command // empty' 2>/dev/null); case \"$CMD\" in -*) exit 0 ;; esac; echo \"$INPUT\" | /path/to/rtk-rewrite.sh"
This sanitizer approach has the downside that rtk init -g will overwrite settings.json on re-run, so users must use --no-patch on upgrades or live with manually re-applying the sanitizer.
Reported by
Found via Gemini 3.1 Pro second-opinion review during install on Claude Code v2.1.x. Happy to submit a PR if helpful.
Activity
pszymkowiak commentedon Apr 17, 2026
🔍 Automated Triage
bughighSummary
Flag-injection vulnerability in rtk-rewrite.sh where commands starting with '-' are misinterpreted as CLI flags by
rtk rewrite; fix is a one-line--terminator addition.📁 Relevant files
hooks/rtk-rewrite.shTriaged automatically by wshm · This is an automated analysis, not a human review.
aeppling commentedon May 8, 2026
Not applicable to current installations. This only affects deprecated shell script hooks (
rtk-rewrite.sh). Current RTK uses native binary hooks (rtk hook claude) which are immune — command is extracted from JSON directly, no clap CLI parsing involved. Please upgrade to latest version and runrtk init -gto migrate.fix(hook): prevent flag injection in rtk-rewrite hooks (rtk-ai#1350)
fix(hook): prevent flag injection in rtk-rewrite hooks (rtk-ai#1350)
fix(hook): prevent flag injection in rtk-rewrite hooks (rtk-ai#1350)
fix(hook): prevent flag injection in rtk-rewrite hooks (rtk-ai#1350)
KuSh commentedon Aug 12, 2026
Hi, closing to avoid more contributions to that legacy issue