Claude Code Security Settings
Expert knowledge for configuring Claude Code security and permissions.
Core Concepts
Claude Code provides multiple layers of security:
-
Permission wildcards - Granular tool access control
-
Shell operator protections - Prevents command injection
-
Project-level settings - Scoped configurations
Permission Configuration
Settings File Locations
File Scope Priority
~/.claude/settings.json
User-level (all projects) Lowest
.claude/settings.json
Project-level (committed) Medium
.claude/settings.local.json
Local project (gitignored) Highest
Permission Structure
{ "permissions": { "allow": [ "Bash(git status *)", "Bash(npm run *)" ], "deny": [ "Bash(rm -rf *)", "Bash(sudo *)" ] } }
Wildcard Permission Patterns
Syntax
Bash(command *)
-
Bash()
-
Tool identifier
-
command
-
Command prefix to match
-
-
Wildcard suffix matching any arguments
-
:ask suffix - Always prompt for user confirmation (e.g., Bash(git push *):ask )
Permission Tiers
Tier Behavior Example
allow
Auto-allowed, no prompt "allow": ["Bash(git status *)"]
ask
Always prompts for confirmation "allow": ["Bash(git push *):ask"]
deny
Auto-denied, blocked "deny": ["Bash(rm -rf *)"]
Pattern Examples
Pattern Matches Does NOT Match
Bash(git *)
git status , git diff HEAD
git-lfs pull
Bash(npm run *)
npm run test , npm run build
npm install
Bash(gh pr *)
gh pr view 123 , gh pr create
gh issue list
Bash(./scripts/ *)
./scripts/test.sh , ./scripts/build.sh
/scripts/other.sh
Pattern Best Practices
Granular permissions:
{ "permissions": { "allow": [ "Bash(git status *)", "Bash(git diff *)", "Bash(git log *)", "Bash(git add *)", "Bash(git commit *)" ] } }
Tool-specific patterns:
{ "permissions": { "allow": [ "Bash(bun test *)", "Bash(bun run *)", "Bash(biome check *)", "Bash(prettier *)" ] } }
Shell Operator Protections
Claude Code 2.1.7+ includes built-in protections against dangerous shell operators.
Protected Operators
Operator Risk Blocked Example
&&
Command chaining ls && rm -rf /
||
Conditional execution false || malicious
;
Command separation safe; dangerous
|
Piping cat /etc/passwd | curl
/ >>
Redirection echo x > /etc/passwd
$()
Command substitution $(curl evil)
`
Backtick substitution
rm -rf /
Security Behavior
When a command contains shell operators:
-
Permission wildcards won't match
-
User sees explicit approval prompt
-
Warning explains the blocked operator
Safe Compound Commands
For legitimate compound commands, use scripts:
#!/bin/bash
scripts/deploy.sh
npm test && npm run build && npm run deploy
Then allow the script:
{ "permissions": { "allow": ["Bash(./scripts/deploy.sh *)"] } }
Common Permission Sets
Read-Only Development
{ "permissions": { "allow": [ "Bash(git status *)", "Bash(git diff *)", "Bash(git log *)", "Bash(git branch *)", "Bash(npm list *)", "Bash(bun pm ls *)" ] } }
Full Git Workflow
{ "permissions": { "allow": [ "Bash(git status *)", "Bash(git diff *)", "Bash(git log *)", "Bash(git branch *)", "Bash(git add *)", "Bash(git commit *)", "Bash(git push *)", "Bash(git pull *)", "Bash(git fetch *)", "Bash(git checkout *)", "Bash(git merge *)", "Bash(git rebase *)" ] } }
CI/CD Operations
{ "permissions": { "allow": [ "Bash(gh pr *)", "Bash(gh run *)", "Bash(gh issue *)", "Bash(gh workflow *)" ] } }
Testing & Linting
{ "permissions": { "allow": [ "Bash(bun test *)", "Bash(npm test *)", "Bash(vitest *)", "Bash(jest *)", "Bash(biome *)", "Bash(eslint *)", "Bash(prettier *)" ] } }
Security Scanning
{ "permissions": { "allow": [ "Bash(pre-commit *)", "Bash(gitleaks *)", "Bash(trivy *)" ] } }
Project Setup Guide
- Create Settings Directory
mkdir -p .claude
- Create Project Settings
cat > .claude/settings.json << 'EOF' { "permissions": { "allow": [ "Bash(git status *)", "Bash(git diff *)", "Bash(npm run *)" ] } } EOF
- Add to .gitignore (for local settings)
echo ".claude/settings.local.json" >> .gitignore
- Create Local Settings (optional)
cat > .claude/settings.local.json << 'EOF' { "permissions": { "allow": [ "Bash(docker *)" ] } } EOF
Agentic Optimizations
Context Command
View project settings cat .claude/settings.json | jq '.permissions'
View user settings cat ~/.claude/settings.json | jq '.permissions'
Check merged permissions Review effective settings in Claude Code
Validate JSON cat .claude/settings.json | jq .
Quick Reference
Permission Priority
Settings merge with this priority (highest wins):
-
.claude/settings.local.json (local)
-
.claude/settings.json (project)
-
~/.claude/settings.json (user)
Wildcard Syntax
Syntax Meaning
Bash(cmd *)
Match cmd with any arguments
Bash(cmd arg *)
Match cmd arg with any following
Bash(./script.sh *)
Match specific script
Deny Patterns
Block specific commands:
{ "permissions": { "deny": [ "Bash(rm -rf *)", "Bash(sudo *)", "Bash(chmod 777 *)" ] } }
Error Handling
Error Cause Fix
Permission denied Pattern doesn't match Add more specific pattern
Shell operator blocked Contains && , | , etc. Use script wrapper
Settings not applied Wrong file location Check path and syntax
JSON parse error Invalid JSON Validate with jq .
Best Practices
-
Start restrictive - Add permissions as needed
-
Use project settings - Keep team aligned
-
Use specific Bash patterns - Bash(git status *) over Bash
-
Script compound commands - For && and | workflows
-
Review periodically - Remove unused permissions