Security Practices¶
Claude Code has deep access to your development environment -- it can read files, execute commands, and interact with external services through MCP servers. This power demands careful security practices. This guide covers how to protect secrets, limit exposure, and audit what Claude does in your projects.
Secrets Management¶
Never hardcode tokens, API keys, or credentials in any file that Claude Code reads or that gets committed to version control. This includes CLAUDE.md, claude_internal/settings.json, and MCP server configurations.
Bad -- token hardcoded in MCP config:
json
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "ghp_a1b2c3d4e5f6g7h8i9j0realtoken"
}
}
}
}
Good -- token referenced from environment variable:
json
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_TOKEN": "${GITHUB_TOKEN}"
}
}
}
}
Store actual values in a .env file and make sure it is listed in .gitignore:
```bash
.env (never committed)¶
GITHUB_TOKEN=ghp_a1b2c3d4e5f6g7h8i9j0realtoken DATABASE_URL=postgres://user:pass@localhost/mydb ```
The claude_internalignore File¶
The claude_internalignore file tells Claude Code which files and directories to skip entirely. It uses the same syntax as .gitignore and should be placed at your project root.
Claude Code will not read, index, or reference any file that matches a pattern in claude_internalignore. This is your primary tool for keeping sensitive files out of the context window.
Example claude_internalignore:
.env
.env.*
credentials/
*.pem
*.key
secrets.yaml
node_modules/
Place this file at the root of your repository alongside CLAUDE.md. It applies recursively to subdirectories. Use it liberally -- there is no cost to ignoring files that Claude does not need.
What NOT to Expose to Claude¶
Even with claude_internalignore in place, be deliberate about what data enters your Claude Code sessions.
| Data Type | Risk | Mitigation |
|---|---|---|
| API keys / tokens | Leakage into context, accidental commit | .env + claude_internalignore + .gitignore |
| Database credentials | Unauthorized access to data stores | Environment variables, vault references |
| PII / customer data | Privacy violations, regulatory exposure | Use anonymized seed data for development |
| Production configs | Accidental changes to live systems | Separate prod configs, restrict file access |
| Private keys / certificates | Complete compromise of encrypted channels | Store outside repo, use claude_internalignore |
Safe Permission Patterns¶
Apply the principle of least privilege when configuring Claude Code permissions.
Default to a restrictive mode for sensitive repositories. Only allowlist commands you have reviewed and trust. Never grant broad shell access on projects that contain production credentials or infrastructure code.
| Scenario | Recommended Permission Mode |
|---|---|
| Open-source library development | Default (prompt per action) |
| Application with secrets in env | Default with specific allowlist |
| Infrastructure / DevOps repo | Restricted -- allowlist only read + lint |
| Quick prototyping (no secrets) | Permissive is acceptable |
| CI/CD pipeline integration | Locked to specific commands only |
Key rules:
- Allowlist only safe, read-only, or idempotent commands like
npm test,npm run lint, andtsc --noEmit. - Never use
--dangerously-skip-permissionson repositories that contain production code, secrets, or infrastructure definitions. - Review your
claude_internal/settings.jsonallowlist periodically to remove stale entries. - When in doubt, keep the default prompt-per-action mode -- the small friction is worth the safety.
Disabling Inline Shell Execution in Skills¶
Skills, custom slash commands, and plugin commands can contain inline shell snippets that Claude Code will execute when the command is invoked. On a machine that has any third-party plugin installed -- even one you trust -- this is a meaningful attack surface: a future plugin update can quietly add a shell snippet that runs the next time the command fires.
disableSkillShellExecution (added in Claude Code v2.1.139) turns the entire mechanism off. Skills still load, descriptions still match, but inline shell stops being a thing the model can use.
json
{
"disableSkillShellExecution": true
}
Set this in ~/claude_internal/settings.json (applies to every project) or claude_internal/settings.json for a specific repo. The right default depends on who controls the skills you have installed:
| Scenario | Recommendation |
|---|---|
| You only run skills you personally wrote | Leave enabled |
| You have any third-party plugin or skill installed | Enable disableSkillShellExecution |
| Shared dev machines, contractor laptops, anything multi-tenant | Enable disableSkillShellExecution in the global config |
| Production-credential repos | Enable, regardless of plugin trust |
What you lose: skills that legitimately depend on inline shell will stop working until you rewrite them to use the Bash tool through the normal allowlist (which is auditable per-command). What you gain: a future malicious or compromised plugin cannot add a one-line curl ... | sh to a SKILL.md and have it execute.
Auditing Claude's Actions¶
Trust but verify. Claude Code provides several mechanisms for reviewing what it has done.
Use PostToolUse hooks to log actions. You can configure hooks that run after every tool invocation, capturing what files were edited or what commands were executed. See hooks.md for configuration details.
Always review diffs before committing. After a Claude Code session, inspect changes carefully:
```bash
See all uncommitted changes¶
git diff
See a summary of changed files¶
git diff --stat
Review the last commit if Claude already committed¶
git log -1 --stat git diff HEAD~1 ```
Check for unintended file creation. Claude may create files you did not expect. Use git status to catch untracked files before staging.
Review MCP server interactions. If Claude used external tools through MCP servers, verify the results are correct. MCP actions may have side effects beyond your local filesystem.
Security Checklist¶
- All secrets are in
.envfiles, never inCLAUDE.mdor committed configs -
.envand credential files are listed in both.gitignoreandclaude_internalignore - MCP server configs reference environment variables, not literal tokens
-
claude_internalignorecovers sensitive directories (credentials/,*.pem,*.key) - Permission mode is appropriate for the repository's sensitivity level
- Tool allowlist includes only safe, reviewed commands
-
--dangerously-skip-permissionsis never used on production repos -
disableSkillShellExecutionis set when third-party plugins or skills are installed - PostToolUse hooks log actions for audit trails
- All diffs are reviewed before commits are pushed
- Team members understand and follow these practices
See Also¶
- Permission Modes -- configuring and understanding permission levels
- CI and Automation -- safe use of --dangerously-skip-permissions in pipelines
- MCP Servers -- secure configuration of external tool servers
- Enterprise Patterns -- governance and compliance at org scale
- Hooks -- setting up audit logging with PostToolUse hooks