CC
Claude Code
v2.1.88
Claude CodePermissions

Permissions

5 layers

Every tool call passes through a 5-layer gauntlet — from AST parsing to ML classifiers to interactive dialogs. Claude Code's security is thorough by design.

TL;DR — Key Takeaways
  • Every Bash command passes through 5 layers: mode check → allow-list → AST analysis → yoloClassifier (ML) → interactive dialog. You can't skip layers.
  • yoloClassifier is a real ML model in production code. It decides if a shell command is safe enough to auto-approve in auto-mode, based on command patterns.
  • The permission system has 4 modes (default, plan, acceptEdits, bypassPermissions) plus org-level overrides via MDM. Each has a different risk profile.
5
Security layers
300KB+
BashTool security code
6
Permission modes
3
HackerOne patches
yoloClassifier🔥 Production ML
utils/permissions/yoloClassifier.ts →

The ML classifier is literally named yoloClassifier. Anthropic engineers named a production safety system after an internet meme. It auto-approves safe patterns like 'git status' or 'ls'.

Safety confidenceYOLO → allow
git status, ls, cat → ✓ auto-allow

When you run rm -rf, here is what happens at each layer before execution. Most calls are resolved before reaching Layer 5.

tool call arrives
1
validateInput()

Pre-checks: file exists, path safe, not stale. Returns error early if failed.

ALLOW
exit ✓
DENY
exit ✗
no decision → pass to next layer
2
checkPermissions()

Tool-specific rules. BashTool: AST shell parsing, dangerous pattern detection, redirect analysis → allow/deny/ask/passthrough.

ALLOW
exit ✓
DENY
exit ✗
no decision → pass to next layer
3
ML Classifier (opt-in)

AI safety scoring. Auto-approves safe patterns like 'git status' or 'ls'. Only available in 'auto' mode via tryClassifier().

ALLOW
exit ✓
DENY
exit ✗
no decision → pass to next layer
4
Permission Hooks

Custom logic from settings.json. Shell commands evaluate tool safety → allow, deny, or escalate to user.

ALLOW
exit ✓
DENY
exit ✗
no decision → pass to next layer
5
User UI Dialog

Interactive confirmation if no auto-decision reached. Shows tool name + input, asks allow/deny, can save as persistent rule.

ALLOW
exit ✓
DENY
exit ✗
layer 5: user dialog (last resort)
default
Safe

Ask user for each potentially unsafe operation

plan
Safe

All tools require explicit plan approval first

acceptEdits
Moderate

Auto-approve file edits without asking

bypassPermissions
Dangerous

Auto-approve everything (dangerous!)

dontAsk
Restrictive

Auto-deny everything silently

auto
AI-gated

ML 'yoloClassifier' auto-approval

Rules are defined in settings.json with three possible behaviors: allow, deny, ask.

typescript
// Permission rule examples:

// Tool name targeting
{ "tool": "Bash", "behavior": "ask" }

// Tool + pattern targeting
{ "tool": "Bash", "pattern": "git *", "behavior": "allow" }
// → Only allow git commands automatically

// File path targeting
{ "tool": "Edit", "pattern": "~/.claude/*", "behavior": "allow" }
// → Auto-approve edits only in .claude folder

// Wildcard patterns
{ "tool": "Bash", "pattern": "*test*", "behavior": "allow" }
// → Allow any command containing "test"

// Bash permission rule matching order:
1. Exact match: "git"
2. Prefix match: "git *" (any git subcommand)
3. Wildcard: "*test*" (contains pattern)

Permission Result Types

typescript
type PermissionResult =
  | { behavior: 'allow'; message?: string }     // Auto-approve
  | { behavior: 'deny'; message: string }        // Block with reason
  | { behavior: 'ask'; message: string }          // Show user dialog
  | { behavior: 'passthrough' }                   // No special handling

// PermissionContext provides:
tryClassifier()        // Await ML-based safety results
runHooks()             // Execute permission hooks
persistPermissions()   // Save updates to disk
buildAllow() / buildDeny()  // Decision factories
handleUserAllow()      // Log + state update
pushToQueue()          // Queue management for UI

Filesystem Permission Checks

File operations go through additional path-level security checks:

typescript
// filesystem.ts — checkWritePermissionForTool()

Blocked paths:
  .gitconfig, .bashrc, .zshrc, .profile  // Shell configs
  .git/*, .vscode/*, .idea/*             // IDE/VCS internals
  /etc/*, /usr/*                          // System directories

Blocked patterns:
  Files matching deny rules from toolPermissionContext
  Files outside allowed working directories

// checkReadPermissionForTool()
  Respects deny rules
  Enforces file read ignore patterns (node_modules, .git)

// FileReadTool blocked devices (would hang process):
  /dev/zero, /dev/random, /dev/urandom    // Infinite output
  /dev/stdin, /dev/tty                     // Blocking input
  /proc/self/fd/*                          // stdio aliases