Bash Security
Bash 安全系统采用 5 层独立的深度防御。即使一层被绕过,其他层仍继续阻止攻击 — 从注入验证器和路径约束到沙箱隔离和环境清理。
架构 — 5 层
命令执行管道
注入的环境变量
| SHELL | Shell 二进制路径 |
| GIT_EDITOR | 'true' — 阻止交互式 git 编辑器 |
| CLAUDECODE | '1' — 通知 CLI 它们在 Claude Code 内 |
| CLAUDE_CODE_SESSION_ID | 会话 ID(仅内部用户) |
超时系统
sleep 在 DISALLOWED_AUTO_BACKGROUND_COMMANDS 中 — 从不自动后台Security Validators (22+)
Early validators (short-circuit on allow)
| # | Validator | What it catches |
|---|---|---|
| 1 | validateEmpty | 空命令 → 允许 |
| 2 | validateIncompleteCommands | 以制表符、标志、运算符开头的片段 |
| 3 | validateSafeCommandSubstitution | 安全的 heredoc-in-substitution 模式 |
| 4 | validateGitCommit | 带简单引号消息的 git commit |
Main validators — misparsing attacks
| # | Validator | What it catches |
|---|---|---|
| 5 | validateJqCommand | system()、-f/--from-file |
| 6 | validateObfuscatedFlags | 标志名称中的引号字符 |
| 7 | validateShellMetacharacters | 参数中的 ;、|、& |
| 8 | validateDangerousVariables | 重定向/管道上下文中的变量 |
| 9 | validateCommentQuoteDesync | 导致引号跟踪脱节的 # |
| 10 | validateQuotedNewline | 引号内分隔命令的换行符 |
| 11 | validateCarriageReturn | CR shell-quote / bash 分词差异 |
| 12 | validateNewlines | 分隔命令的换行符(非误解析) |
| 13 | validateIFSInjection | $IFS 变量使用 |
| 14 | validateProcEnvironAccess | /proc/*/environ 访问 |
| 15 | validateDangerousPatterns | 反引号、$()、$${}、$[]、Zsh 展开 |
| 16 | validateRedirections | 输入 < 和输出 > 重定向(非误解析) |
| 17 | validateBackslashEscapedWhitespace | 反斜杠空格绕过 |
| 18 | validateBackslashEscapedOperators | \;、\| 等 |
| 19 | validateUnicodeWhitespace | 非 ASCII 空白字符 |
| 20 | validateMidWordHash | 引号附近的 # |
| 21 | validateBraceExpansion | 花括号展开模式 {a,b} |
| 22 | validateZshDangerousCommands | zmodload、emulate、sysopen 等(20 个命令) |
| 23 | validateMalformedTokenInjection | 不平衡分隔符 + 分隔符(HackerOne eval 绕过) |
Misparsing vs non-misparsing
Misparsing validators Their ask results set isBashSecurityCheckForMisparsing: true, causing early blocking in the permission flow. Catch attacks that exploit differences between how the security parser and actual bash tokenize commands.
Non-misparsing validators validateNewlines and validateRedirections — results are deferred to ensure misparsing validators still run first.
Quote extraction — 3 views
View What it does withDoubleQuotes 移除单引号,保留双引号 fullyUnquoted 移除所有引号内容 unquotedKeepQuoteChars 移除内容但保留引号分隔符
Safe redirection stripping
stripSafeRedirections() removes known-safe patterns:
✓ 2>&1 (stderr to stdout) ✓ >/dev/null or 2>/dev/null ✓ </dev/null (empty stdin) Each pattern requires trailing boundary (?=\s|$) to prevent prefix attacks (e.g., >/dev/nullo would write to file nullo).
Permission Flow & Read-Only Commands
bashToolHasPermission() — 8-step pipeline
1. checkPermissionMode() — acceptEdits → auto-allow mkdir, touch, rm, etc. 2. checkReadOnlyConstraints() — Parse command → if proven read-only → allow 3. bashCommandIsSafeAsync() — Run all 22+ validators → any "ask" → block with reason 4. checkPathConstraints() — Extract paths → validate within allowed directories 5. checkSedConstraints() — Special handling for sed -i in-place edits 6. Permission rule matching — Check allow rules (prefix), check deny rules 7. Sandbox auto-allow — If sandboxed + autoAllowBashIfSandboxed → allow 8. ML Classifier (feature-gated) — ANT-only: bash classifier model → allow/deny Compound command handling
Commands with &&, ||, ;, | are split via splitCommand_DEPRECATED(). Cap of 50 subcommands prevents CPU exhaustion. If any subcommand fails → entire command blocked.
Read-only command allowlist
File operations: ls, cat, head, tail, wc, file, stat, du, df, find, tree, realpath, md5sum, sha256sum, xxd Text processing: grep, rg, awk, sed (no -i), sort, uniq, cut, tr, diff, comm, jq, yq, xq, column Git (read): git status, git log, git diff, git show, git branch, git tag, git blame, git shortlog Development: node -e, python -c, tsc --noEmit, eslint, prettier --check, cargo check, go vet System: echo, printf, date, env, which, type, uname, hostname, whoami, id, pwd, test Per-command flag validation
fd -x / -X — excluded: --exec / --exec-batch trigger code execution fd -l — excluded: internally executes ls subprocess (PATH hijacking risk) jq — blocks system(), -f, --from-file sed -i — in-place edit: NOT read-only, requires explicit permission Path Validation & Filesystem Protection
Per-command path extractors (30+ commands)
Commands Path extraction strategy cd, ls, cat, head, tail 标志剥离后的位置参数 rm, rmdir, mkdir, touch 所有非标志参数 mv, cp 源和目标参数 find 第一个参数(搜索根) grep, rg 模式后的文件参数 sed -i 目标文件 git 子命令特定提取 jq 输入文件参数
POSIX -- end-of-options handling
filterOutFlags() correctly handles --: after it, ALL arguments are treated as paths, preventing:
rm -- -/../.claude/settings.local.json
# "-/../.claude/..." is a PATH, caught as traversal
Protected files & directories
Protected files (auto-edit blocked)
.gitconfig, .gitmodules, .bashrc, .bash_profile, .zshrc, .zprofile, .profile, .ripgreprc, .mcp.json, .claude.json
Protected directories
.git, .vscode, .idea, .claude
Claude config (extra protection)
.claude/settings.json, .claude/settings.local.json, .claude/commands/, .claude/agents/, .claude/skills/
Path safety checks
Check What it catches NTFS ADS 位置 2 之后的 :(备用数据流) 8.3 短名称 ~\d 模式(Windows 短文件名) 长路径前缀 \\?\、\\.\(Windows 扩展) DOS 设备名 CON、PRN、AUX、NUL 等 三点 路径组件中的 ... 符号链接解析 原始路径和解析目标都检查 大小写规范化 normalizeCaseForComparison() 全部小写
Sandbox & Environment Security
Sandbox platforms
Platform Technology Status macOS seatbelt (sandbox-exec) 内置 Linux bubblewrap (bwrap) 需要安装 WSL2 bubblewrap 需要安装 Windows 原生 — 不支持
Sandbox decision flow
1. Sandboxing enabled? → No → no sandbox 2. dangerouslyDisableSandbox: true + areUnsandboxedCommandsAllowed() → no sandbox 3. Command in excludedCommands list? → no sandbox 4. Apply SandboxManager.wrapWithSandbox() excludedCommands is NOT a security boundary — permission system still applies.
Bare git repo defense
Sandbox blocks writes to git-structural files at CWD: HEAD, objects/, refs/, hooks/, config. Post-command, scrubBareGitRepoFiles() deletes any planted files. Prevents attackers from planting malicious git hooks.
Subprocess env scrubbing
Activated when CLAUDE_CODE_SUBPROCESS_ENV_SCRUB is set (GitHub Actions context):
Category Variables stripped Anthropic ANTHROPIC_API_KEY, CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_AUTH_TOKEN AWS AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_BEARER_TOKEN_BEDROCK GCP/Azure GCP/Azure 凭证变量 GitHub Actions ACTIONS_ID_TOKEN_REQUEST_TOKEN, 运行时令牌 OTEL 可能包含认证令牌的头 INPUT_* 上述所有 INPUT_ 前缀变体
Variables NEVER safe to strip
Category Variables Risk 执行 PATH, LD_PRELOAD, LD_LIBRARY_PATH, DYLD_* 二进制/库劫持 模块加载 PYTHONPATH, NODE_PATH, CLASSPATH, RUBYLIB 通过导入注入代码 代码执行 GOFLAGS, RUSTFLAGS, NODE_OPTIONS 通过标志执行任意代码 系统 HOME, TMPDIR, SHELL, BASH_ENV 行为修改
Dangerous Patterns, PowerShell & Destructive Warnings
Dangerous command patterns
Cross-platform (code execution)
python, python3, node, deno, tsx, ruby, perl, php, lua, npx, bunx, npm run, yarn run, bash, sh, ssh
Unix additions
zsh, fish, eval, exec, env, xargs, sudo
Zsh-specific (20 builtins)
zmodload, emulate, sysopen, syswrite, ztcp, zsocket, zf_rm, zf_mkdir, zf_rmdir, zf_ln, zf_mv, zf_chmod…
Destructive command warnings
Git: git reset --hard, git push --force, git clean -f, git checkout ., git stash drop/clear, git branch -D, git commit --amend Filesystem: rm -rf, rm -r, rm -f Database: DROP TABLE/DATABASE, TRUNCATE TABLE, DELETE FROM Infrastructure: kubectl delete, terraform destroy These are informational warnings in the permission dialog — not security blocks.
PowerShell security (parallel system)
Mirrors the Bash system with platform-specific adaptations: per-cmdlet CmdletPathConfig, case-insensitive matching, GIT_SAFETY_WRITE_CMDLETS, archive extractor detection.
PowerShell dangerous patterns
pwsh, powershell, cmd, wsl, iex, invoke-expression, start-process, saps, start-job, sajb, register-objectevent
PowerShell auto-mode block categories (4)
1 Download-and-Execute: iex (iwr ...) — equivalent to curl | bash 2 Irreversible Destruction: Remove-Item -Recurse -Force — equivalent to rm -rf 3 Persistence: Modifying $PROFILE, Register-ScheduledTask, registry Run keys 4 Elevation: Start-Process -Verb RunAs, -ExecutionPolicy Bypass, disable AMSI/Defender 12 Security Design Principles
1. Defense in Depth Multiple independent layers each block attacks. Bypassing one layer doesn't compromise the others.
2. Fail-Safe Defaults Unknown parameters, parse failures, complex commands → ask. The system never assumes safety.
3. Misparsing Awareness Validators explicitly account for differences between security parser and actual bash tokenization.
4. Case-Insensitive Paths normalizeCaseForComparison() applied everywhere to prevent macOS/Windows case-based bypasses.
5. Symlink Resolution Both original path AND resolved target checked for all security decisions.
6. No Trust in User Controls excludedCommands is explicitly NOT a security boundary — security comes from the permission system.
7. Subprocess Env Scrubbing API keys and CI tokens stripped from subprocess envs in GitHub Actions contexts.
8. Bare Git Repo Defense Sandbox blocks writes to git-structural files. Post-command scrubbing removes any planted files.
9. Per-Process Nonces Bundled skills root uses randomBytes(16) to prevent pre-creation attacks on shared /tmp.
10. Compound Command Splitting &&, ||, ;, | operators parsed — each subcommand validated independently. Cap of 50 prevents CPU exhaustion.
11. Quote Context Tracking 3 views of each command enable precise detection of metacharacters hidden in quoted contexts.
12. Boundary Assertions Safe redirection stripping requires trailing boundaries (?=\s|$) to prevent prefix attacks.
i Output handling
Tool results > 30,000 chars are persisted to file; > 64 MB is the maximum persisted size.
The EndTruncatingAccumulator keeps the beginning and end of output, truncating the middle with
[... truncated ...]. Large outputs get a preview with a pointer to the full file for the Read tool.