Bash Security Pipeline
The shell command security system in claude-code, implemented in bashSecurity.ts (2,308 lines). Runs 25+ validators in a specific chain to evaluate every shell command before execution.
The Validator Chain
Validators run sequentially at bashSecurity.ts:2308-2378. Three structural vulnerabilities are documented in the source itself:
1. Early-Allow Short-Circuits
validateGitCommit and validateSafeCommandSubstitution can return allow, which bypasses all subsequent validators. The source contains its own warning:
"validateGitCommit returns allow -> bashCommandIsSafe short-circuits -> validateRedirections NEVER runs -> ~/.bashrc overwritten"
2. Three-Parser Differentials
Commands are parsed by three different parsers with different edge-case behavior:
| Parser | Used For |
|---|---|
splitCommand_DEPRECATED |
Legacy command splitting |
tryParseShellCommand |
Modern parsing |
ParsedCommand.parse |
Structured parsing |
A known differential: "shell-quote's [^\s] treats CR as a word separator (JS \s ⊃ \r), but bash IFS does NOT include CR." Attackers can exploit differences between what the validator thinks a command does and what bash actually executes.
3. Non-Misparsing Result Discardal
validateRedirections catches a dangerous > redirect, but if no "misparsing" validator fired, the result lacks isBashSecurityCheckForMisparsing. The permission-pipeline discards the warning if the user has a matching allow rule. Result: echo "payload" > ~/.bashrc passes the entire chain if the user has Bash(echo:*) allowed.
The 50-Subcommand Cap (CVE)
const MAX_SAFE_CHECK_SUBCOMMANDS = 50
// 50 is a generous allowance for legitimate usage.
// After 50, fall back to ask-permission rather than deny.
Adversa AI's exploit: 49 true no-ops + malicious curl = 50 subcommands. The parser sees 51, exceeds the cap, and falls through from deny to ask-permission. In CI/CD or --dangerously-skip-permissions mode, no human sees the prompt.
The assumption was correct for human-authored commands. It didn't account for AI-generated command sequences from prompt injection — where a malicious CLAUDE.md instructs the AI to generate a 50+ subcommand pipeline that looks like a legitimate build process.
Patched silently in v2.1.90. The tree-sitter AST parser (already in bashSecurity.ts) could have fixed this with a one-line change: deny-on-overflow instead of ask-on-overflow.
The CVE Cluster
| CVE | CVSS | Mechanism | Fixed |
|---|---|---|---|
| CVE-2025-59536 | 8.7 | Pre-trust hook execution — RCE before trust dialog | v1.0.111 |
| CVE-2026-21852 | 5.3 | ANTHROPIC_BASE_URL redirect exfiltrates API key |
v2.0.65 |
| CVE-2025-54795 | 8.7 | Confirmation prompt bypass via prompt crafting | v1.0.20 |
| Adversa deny-cap bypass | TBD | 50-subcommand overflow | v2.1.90 |
| CVE-2026-35020/21/22 | TBD | Command injection in which.ts, promptEditor.ts, auth.ts | Unpatched |
Common root cause: the safety enforcement boundary is inside the model's reasoning layer, not below it.
Key Claims
clm-20260409-55bcc37ee526: 50-subcommand cap causes deny-to-ask downgradeclm-20260409-526d16839a31: Safety mechanism and attack surface are the same thing
Sources
src-20260409-6913a0b93c8b— Round 7: The Deepest Architecture Yetsrc-20260409-cbf9b6837f5f— Round 10: Quality Gap, CVE, Security