[BUG] `$ARGUMENTS` in slash commands not escaped for bash execution
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When using $ARGUMENTS in custom slash commands (.claude/commands/*.md) with bash execution syntax (!`command`), user input is passed to bash without any escaping or sanitization.
This causes:
- Syntax errors with quotes, apostrophes, and other shell meta-characters
- Command injection vulnerabilities via
$, backticks, and other special characters - Inconsistent behaviour - the bundled
shell-quotelibrary is used elsewhere in the codebase but not for$ARGUMENTSsubstitution
What Should Happen?
The command should output: don't try this
User input in $ARGUMENTS should be properly escaped for bash execution using the already-bundled shell-quote library, preventing both syntax errors and command injection.
Error Messages/Logs
For example, running `/test-bash-args don't try this` produces:
Error: Bash command failed for pattern "!`echo don't try this`": [stderr]
/bin/bash: eval: line 1: unexpected EOF while looking for matching `''
Steps to Reproduce
- Create
.claude/commands/test-bash-args.md:
---
description: Test $ARGUMENTS passed to bash
allowed-tools: Bash(echo:*)
---
# Test Bash Arguments
Command output: !`echo $ARGUMENTS`
-
Restart Claude Code to load the new command
-
Run the command with an apostrophe:
$ claude
> /test-bash-args don't try this
- Observe the bash syntax error
Additional test cases that fail:
| Input | Issue |
|---|---|
can't go |
Syntax error: unmatched quote |
$(whoami) |
Command injection via $() |
`whoami` |
Command injection via backticks |
$HOME |
Variable expansion |
test;ls |
Command chaining |
Claude Model
Sonnet (default)
Is this a regression?
No, this never worked
Last Working Version
No response
Claude Code Version
2.0.76 (Claude Code)
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Xterm
Additional Information
Root Cause Analysis
Investigation process (reproducible):
- Version: v2.0.76
- Beautifier: js-beautify v1.14.11
- Command:
js-beautify ~/.npm-global/lib/node_modules/@anthropic-ai/claude-code/cli.js > output.js
Key findings in beautified code:
Line 277247 - $ARGUMENTS substitution uses simple replaceAll() with NO escaping:
if (R)
if (P.includes("$ARGUMENTS")) P = P.replaceAll("$ARGUMENTS", R);
Line 49020-49029 - shell-quote library IS bundled but NOT used for $ARGUMENTS:
var kBQ = U((Vd7, vBQ) => {
vBQ.exports = function(Q) {
return Q.map(function(B) {
if (B === "") return "''";
// ... proper escaping of ", \, $, `, !, #, &, ', etc.
}).join(" ")
}
});
Line 49193-49208 - shell-quote is ALREADY used elsewhere in the codebase (function t6()).
Production Commands Avoid This Pattern
Analysis of all production commands in the repository (/.claude/commands/*.md) shows NONE pass $ARGUMENTS to bash execution:
clean_gone.md- Uses static bash commands onlycommit-push-pr.md- Uses bash for info gathering (!`git status`), not with user argsdedupe.md- Static bash commandsoncall-triage.md- Static bash commands
This appears to be a known design limitation - production commands carefully avoid passing $ARGUMENTS to bash.
Proposed Solution
Use the existing bundled shell-quote library to escape $ARGUMENTS before substitution:
if (R)
if (P.includes("$ARGUMENTS")) {
let escapedArgs = G5A.quote([R]); // Use shell-quote
P = P.replaceAll("$ARGUMENTS", escapedArgs);
}
Benefits:
- ✅ Makes
$ARGUMENTSsafe to use in bash commands - ✅ Would enable implementation of
$1,$2,$3(currently documented but not implemented - likely for this same reason) - ✅ No new dependencies (library already bundled)
- ✅ Consistent with existing
t6()function behavior
Why $1, $2, $3 Don't Exist
The documentation mentions positional arguments $1, $2, $3, but:
- ❌ No implementation exists in the code
- ❌ Empirical testing shows they remain as literal text
- ❌ Issue #8406 (Sept 2025) shows users trying unsuccessfully to use them
This feature was likely documented but never implemented because it would encourage the same unsafe pattern.
Environment Details
- OS: Linux 6.18.1-local
- Node: v18+
- Installation: npm global (
~/.npm-global/lib/node_modules/@anthropic-ai/claude-code)