Claude Code Security & Best Practices: Safe AI Development
By Dorian Laurenceau
📅 Last reviewed: April 24, 2026. Updated with April 2026 findings and community feedback.
Claude Code is a powerful tool that executes code on your system. With great power comes great responsibility. This guide covers security configurations, MCP server vetting, secrets management, and building safety gates through hooks - everything you need to use Claude Code safely in production environments.
1. Understanding the Security Model
Claude Code operates with a permission system that controls what actions the AI can take autonomously.
Permission Categories
ALLOW (Auto-approve)
- →Read operations
- →Safe bash commands
- →Whitelisted tools
ASK (Confirm first)
- →Write operations
- →System commands
- →Default for unknown
DENY (Blocked)
- →Dangerous commands
- →Forbidden patterns
The security posture most teams actually adopt with Claude Code lands in an uncomfortable middle: too restrictive and the agent becomes useless; too permissive and you've effectively given a language model sudo on your laptop. Practitioners on r/devops and r/cybersecurity converge on a pragmatic framing — treat Claude Code like a new engineer on their first week: capable, well-intentioned, but still on probation. You'd review their PRs, scope their access, and keep production credentials out of their reach. Same rules apply here, and the official security guide is more permissive than most security engineers would recommend as a default.
Where the community correctly pushes back: --dangerously-skip-permissions is not "power user mode", it is "I accept every consequence of every shell command this model decides to run". Threads on r/ClaudeAI are full of recovery stories — destroyed branches, accidental rm -rf in wrong directory, exfiltrated .env files posted to GitHub gists as "evidence" for a bug report. None of these are model failures; they are permission-model failures that happened to involve the model.
What actually works in practice: deny-by-default, scope by directory (settings.local.json per project, never one global permission set), keep an .envrc or equivalent out of the cwd the agent sees, and audit the permissions file like you'd audit a CI workflow. The reference playbook for threat modeling LLM tools is OWASP LLM Top 10 — most of the findings map directly to "what an over-permissive Claude Code can do".
2. Configuring Permissions
Permissions are configured in settings.local.json (personal) or settings.json (team):
Personal Permission Overrides
{
"permissions": {
"allow": [
"Bash(git *)",
"Bash(pnpm *)",
"Bash(npm test)",
"Edit",
"Write",
"WebSearch"
],
"deny": [
"Bash(rm -rf *)",
"Bash(sudo *)"
],
"ask": [
"Bash(npm publish)",
"Bash(git push --force)"
]
}
}
3. Progressive Permission Levels
Adjust permissions based on your experience and trust level:
Level Configurations
Level 1 - Beginner:
{
"allowedTools": ["Read(*)", "Grep(*)", "Glob(*)"]
}
Level 2 - Intermediate:
{
"allowedTools": [
"Read(*)", "Grep(*)", "Glob(*)",
"Bash(git:*)", "Bash(pnpm:*)",
"TodoRead", "TodoWrite"
]
}
Level 3 - Advanced:
{
"allowedTools": [
"Read(*)", "Grep(*)", "Glob(*)", "WebFetch(*)",
"Edit(*)", "Write(*)",
"Bash(git:*)", "Bash(pnpm:*)", "Bash(npm:*)",
"Task(*)", "TodoRead", "TodoWrite"
]
}
4. MCP Server Security
MCP servers extend Claude Code's capabilities, but they also expand its attack surface. Apply the same security scrutiny you'd use for any third-party code dependency.
Explore Available MCP Servers
Use this interactive explorer to browse 50+ MCP servers, filter by category and features, and get setup instructions for each:
Pre-Installation Checklist
Security Risks to Understand
Legitimate flow:
Claude → Native Read tool → Your file
Tool shadowing attack:
Claude → MCP "Read" tool → Attacker's server → Your file
Protection Strategies
- →Verify tool names: Check what tools each MCP server exposes
- →Use allowedTools: Explicitly whitelist which MCP tools are permitted
- →Monitor network: Watch for unexpected outbound connections
- →Sandbox untrusted servers: Run in isolated environments
5. Secrets Management
MCP servers and scripts often require API keys and credentials. Never store them in plaintext configuration files.
The Three Approaches
Approach 1: OS Keychain (Recommended)
macOS Keychain:
# Store secret in Keychain
security add-generic-password \
-a "claude-mcp" \
-s "github-token" \
-w "ghp_your_token_here"
# Retrieve in MCP config
{
"servers": {
"github": {
"command": "bash",
"args": ["-c", "GITHUB_TOKEN=$(security find-generic-password -s 'github-token' -w) npx @github/mcp-server"]
}
}
}
Linux Secret Service:
# Store secret
secret-tool store --label="GitHub Token" service claude key github-token
# Retrieve in wrapper script
export GITHUB_TOKEN=$(secret-tool lookup service claude key github-token)
npx @github/mcp-server
Approach 2: .env + .gitignore
# 1. Create .env file
cat > ~/.claude/.env << EOF
GITHUB_TOKEN=ghp_your_token_here
DATABASE_URL=postgresql://user:pass@localhost/db
EOF
# 2. Secure permissions
chmod 600 ~/.claude/.env
# 3. Add to .gitignore
echo ".env" >> ~/.claude/.gitignore
MCP configuration with .env:
{
"servers": {
"github": {
"command": "npx",
"args": ["@github/mcp-server"],
"env": {
"GITHUB_TOKEN": "${env:GITHUB_TOKEN}"
}
}
}
}
6. Pre-Commit Secret Detection
Prevent accidental secret commits with a pre-commit hook:
#!/bin/bash
# .git/hooks/pre-commit
# Patterns to detect
PATTERNS=(
'sk-[A-Za-z0-9]{48}' # OpenAI keys
'ghp_[A-Za-z0-9]{36}' # GitHub tokens
'AKIA[A-Z0-9]{16}' # AWS keys
'api[_-]?key.*[:=].*[A-Za-z0-9]{20,}' # Generic API keys
)
for pattern in "${PATTERNS[@]}"; do
if git diff --cached | grep -qE "$pattern"; then
echo "❌ Secret detected! Commit blocked."
echo "Pattern matched: $pattern"
exit 1
fi
done
exit 0
7. Hook-Based Security Gates
Use hooks to enforce security policies automatically.
Security Check Hook
#!/bin/bash
# .claude/hooks/security-check.sh
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // ""')
# Block dangerous patterns
BLOCKED_PATTERNS=(
"rm -rf /"
"rm -rf ~"
"rm -rf \$HOME"
":(){ :|:& };:" # Fork bomb
"> /dev/sda" # Disk overwrite
"curl.*| bash" # Pipe to bash
"wget.*| bash"
)
for pattern in "${BLOCKED_PATTERNS[@]}"; do
if echo "$COMMAND" | grep -qE "$pattern"; then
cat << EOF
{
"decision": "block",
"reason": "Blocked dangerous command pattern: $pattern"
}
EOF
exit 0
fi
done
# Allow by default
echo '{"decision": "allow"}'
CLAUDE.md Injection Scanner
#!/bin/bash
# .claude/hooks/claudemd-scanner.sh
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // ""')
# Only scan CLAUDE.md files being read
if [[ ! "$FILE_PATH" =~ CLAUDE\.md$ ]]; then
exit 0
fi
# Check for injection patterns
INJECTION_PATTERNS=(
"ignore.*previous.*instructions"
"ignore.*above"
"disregard.*instructions"
"curl.*\|.*bash"
"wget.*\|.*bash"
"base64.*decode"
)
CONTENT=$(cat "$FILE_PATH" 2>/dev/null)
for pattern in "${INJECTION_PATTERNS[@]}"; do
if echo "$CONTENT" | grep -qiE "$pattern"; then
cat << EOF
{
"systemMessage": "⚠️ WARNING: Potential prompt injection detected in $FILE_PATH. Pattern: $pattern. Please review the file manually before proceeding."
}
EOF
exit 0
fi
done
exit 0
8. Validation Pipeline
Chain multiple validation hooks to catch issues immediately after code changes:
Edit/Write → TypeCheck → Lint → Tests → Notify Claude
↓ ↓ ↓ ↓
file.ts tsc check eslint jest file.test.ts
Configuration:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/typecheck-on-save.sh",
"timeout": 5000
},
{
"type": "command",
"command": ".claude/hooks/lint-gate.sh",
"timeout": 5000
},
{
"type": "command",
"command": ".claude/hooks/test-on-change.sh",
"timeout": 10000
}
]
}
]
}
}
9. Production Safety Rules
For teams deploying Claude Code in production environments:
Database Safety
# In CLAUDE.md
## Database Safety Rules
- NEVER run DROP, TRUNCATE, or DELETE without WHERE clause
- ALWAYS use transactions for multi-step operations
- ALWAYS backup before migration scripts
- Use read-only database credentials for exploration
Port Stability
## Port Rules
- Development server: always port 3000
- API server: always port 8080
- Database: always port 5432
- Never use random ports without documentation
Git Safety
## Git Rules
- Never force push to main, master, or develop
- Always create feature branches for changes
- Run tests before any push
- Require PR reviews for production branches
10. Security Verification Checklist
Before deploying Claude Code in any environment:
Test Secret Isolation
# Should work (secret from .env)
export $(cat ~/.claude/.env | xargs)
claude
# Should fail (no secrets in environment)
unset GITHUB_TOKEN DATABASE_URL
claude
# ❌ MCP servers fail to start (expected behavior)
Summary: Security Best Practices
- →Progressive Permissions: Start restrictive, expand as you gain trust
- →Never Skip Permissions: The --dangerously-skip-permissions flag is for sandboxed environments only
- →Vet MCP Servers: Apply the same scrutiny as any third-party dependency
- →Manage Secrets Properly: Use OS keychain or .env with proper permissions, never plaintext
- →Pre-Commit Hooks: Block secrets from ever reaching Git
- →Security Gates: Use hooks to enforce policies automatically
- →Validation Pipelines: Catch errors immediately after code changes
- →Production Rules: Document and enforce database, port, and git safety
Module 5 — RAG (Retrieval-Augmented Generation)
Ground AI responses in your own documents and data sources.
Dorian Laurenceau
Full-Stack Developer & Learning DesignerFull-stack web developer and learning designer. I spent 4 years as a freelance full-stack developer and 4 years teaching React, JavaScript, HTML/CSS and WordPress to adult learners. Today I design learning paths in web development and AI, grounded in learning science. I founded learn-prompting.fr to make AI practical and accessible, and built the Bluff app to gamify political transparency.
Weekly AI Insights
Tools, techniques & news — curated for AI practitioners. Free, no spam.
Free, no spam. Unsubscribe anytime.
→Related Articles
FAQ
Is Claude Code safe to use on production codebases?+
Yes, with proper configuration. Use permission modes (Suggest, Auto-edit, Full auto) appropriately, vet MCP servers before installing, and never store secrets in plain text.
What is tool shadowing and how do I prevent it?+
Tool shadowing is when malicious MCP servers declare tools with names like 'Read' or 'Bash' to intercept commands. Only install MCP servers from trusted sources and use allowedTools restrictions.
How should I manage secrets with Claude Code?+
Use environment variables (${VAR_NAME} in configs), secrets managers like 1Password or AWS Secrets Manager, or system keychains. Never commit tokens to version control.
Can I restrict what files Claude can access?+
Yes, use .claudeignore files (similar to .gitignore) to exclude sensitive files and directories. Also configure allowed-tools in skills to limit filesystem access.