BashTool

Description

The shell command execution tool — the most complex and security-critical tool in Claude Code. Executes arbitrary bash commands with full system access, subject to a multi-layer security pipeline: permission rules, dangerous pattern detection (23 checks), read-only validation, path constraints, optional ML classification, and sandbox wrapping. Supports streaming output, background execution, auto-backgrounding, and platform-specific shell selection.

Implementation: src/tools/BashTool/ (12,429 lines across all files)

Execution pipeline

Input (command string)
  → validateInput (sleep pattern detection)
  → checkPermissions (compound command parsing, 23 security checks, path validation)
  → shouldUseSandbox (exclusion check)
  → findSuitableShell (bash/zsh detection)
  → buildExecCommand (snapshot + init chain + eval)
  → [if sandbox] wrapWithSandbox (bubblewrap/macOS sandbox)
  → spawn(shell, ['-c', command])
  → streaming output + progress reporting
  → output processing (truncation, image detection, exit code interpretation)
  → result

Security model

23 dangerous pattern checks (bashSecurity.ts)

# Check Purpose
1 Incomplete commands Unclosed quotes/heredocs
2 jq system() Code execution via jq
3 jq file arguments File I/O via jq args
4 Obfuscated flags Hidden flags via backslash escaping
5 Shell metacharacters Pipes, redirections outside quotes
6 Dangerous variables IFS, PATH, LD_PRELOAD assignment
7 Newlines Hidden commands after newlines
8 Command substitution $(), ${}, process substitution
9 Input redirection < for hidden input
10 Output redirection >, >> for file writes
11 IFS injection Field separator manipulation
12 Git commit substitution $(git rev-parse ...) patterns
13 /proc/environ access Reading process environment
14 Malformed token injection Shell quote parser bugs
15 Backslash-escaped whitespace Hidden operators: \ &&
16 Brace expansion {a,b} in sensitive contexts
17 Control characters Non-printing chars (U+0000-U+001F)
18 Unicode whitespace Homoglyphic whitespace (U+00A0)
19 Mid-word hash Comments mid-command
20 Zsh dangerous commands zmodload, emulate, sysopen, etc.
21 Backslash-escaped operators \|, \&& escaping
22 Comment-quote desync Quote state corruption via comments
23 Quoted newline Newlines inside quotes

Compound command parsing

Uses Tree-sitter for AST analysis. Splits &&, ||, ;, | into subcommands. Each subcommand validated independently against permission rules via preparePermissionMatcher. Extracts argv (strips leading VAR=val assignments).

Read-only validation (readOnlyValidation.ts)

Dynamic per-command evaluation determines isConcurrencySafe:

isConcurrencySafe(input) {
  return this.isReadOnly?.(input) ?? false
}

Allowlisted read-only commands with flag whitelisting: git log/show/diff/status, find, grep, rg, fd, cat, head, tail, jq, wc, stat, file, docker ps/inspect, gh (read-only subcommands). Dangerous flags are explicitly blocked (e.g., fd -x/--exec).

Sandbox integration

shouldUseSandbox() checks if sandboxing is enabled, then wraps the command via SandboxManager.wrapWithSandbox() (bubblewrap on Linux, macOS sandbox). Excluded commands configurable via GrowthBook dynamic config and user settings. Sandbox config includes: allowWrite (cwd, temp), denyWrite (settings files, .claude/skills, bare git repo files), network domain restrictions.

Shell selection

Priority: CLAUDE_CODE_SHELL env → $SHELL (if bash/zsh) → which bash/zsh → standard paths. On Windows, uses Git Bash with POSIX path conversion. Shell init chain: source snapshot → source session env (from hooks) → disable extended globs → eval command → capture cwd.

Output handling

Background execution

run_in_background: true spawns as LocalShellTask. Auto-backgrounding for long-running commands (npm, yarn, node, python, docker, cargo, webpack). Background tasks have a size watchdog (5s polling, kills if output exceeds limit).

Platform differences

Aspect Linux/macOS Windows
Shell bash or zsh from PATH Git Bash (POSIX)
Paths Native POSIX Converted via windowsPathToPosixPath
File I/O O_APPEND + O_NOFOLLOW 'w' mode (FILE_GENERIC_WRITE)
Null redirect /dev/null > nul rewritten to > /dev/null
Sandbox bubblewrap Not available

What depends on it

Design trade-offs

Decision Trade-off
23 security pattern checks Defense-in-depth, but validation overhead on every command
Tree-sitter AST parsing Accurate compound command analysis, but parser dependency
Per-command read-only evaluation BashTool can run concurrently for read-only commands, but requires command parsing
Sandbox wrapping Strong isolation, but not available on Windows
Auto-backgrounding Prevents blocking on long commands, but may surprise users
File-based output (not pipes) No JS overhead for large outputs, but requires file polling for progress

Key claims

Relations

Sources

Source code at src/tools/BashTool/, src/utils/Shell.ts, src/utils/sandbox/sandbox-adapter.ts