Protecting Credentials in Claude Code
There is a problem nobody really tells you about.
If you use Claude Code for development, there is something you may not realize: it stores a complete history of your conversations as plain text on your machine. Depending on how you have used it, you may need to review how you handle credentials sooner rather than later.
~/.claude/history.jsonl
~/.claude/file-history/
~/.claude/projects/
On top of that, everything you type into the chat is sent to Anthropic's servers for processing.
That is how the service works — it is not a secret — but it is also something you may not think about while you are in the middle of a coding session.
That is why knowing how to protect credentials when using Claude Code is critical. Or, at the very least, understanding the security practices you should follow.
How to protect credentials in Claude Code
Before looking at detection and remediation, it is useful to understand which configuration files Claude Code uses and where they live.
There are two main types.
~/.claude/settings.json — your personal configuration. It can contain permissions, MCP servers and environment configuration. This is the file you normally edit yourself.
/Library/Application Support/ClaudeCode/managed-settings.json — managed configuration for corporate environments. Administrators can use it to enforce security policies across an organization through MDM.
If you work independently, this file probably does not exist on your machine.
Both files can contain sensitive information if they are not configured carefully — especially settings.json, where it is easy to accidentally end up with hardcoded credentials.
Step 1: Detection
I started by scanning these files for credentials.
I looked for common patterns such as AWS Access Key prefixes (AKIA, AKAR, etc.), GitHub tokens (ghp_) and generic long-format keys.
The result was not particularly surprising.
When configuring connectors or integrations with certain providers, sensitive values can end up stored locally in files used by Claude.
The bigger problem is that the information may not stay there. If you paste credentials into a conversation, that information is also sent to the model provider.
That is the part that should make us think more carefully about how we use coding assistants.
And I do not think this topic is discussed enough.
The rule I ended up with: treat Claude like pair programming over a video call with someone outside your company. You would not show them your keys on screen.
Step 2: Cleanup
The first thing I did was revoke every credential that might have been exposed.
If a key has appeared in plain text, I prefer to consider it compromised even if there is no evidence that somebody actually used it.
Clear the chat history:
~/.claude/history.jsonl
Remove backups of files edited by Claude:
rm -rf ~/.claude/file-history/*
Clear conversations stored by project:
find ~/.claude/projects/ -name "*.jsonl" -exec truncate -s 0 {} \;
Then review the configuration file.
If there are tokens there, remove them:
~/.claude/settings.json
Step 3: Reconfigure using better security practices
Once the credentials had been cleaned up and revoked, the goal was to configure everything again without allowing secret values to appear directly in the chat or in Claude configuration files.
Use a GitHub token with minimum privileges
When configuring a GitHub token for Claude Code, do not enable every permission just because it is convenient.
Apply the principle of least privilege and grant only the permissions you actually need.
For example, when using a classic token with private repositories:
| Scope | Purpose |
| repo | Read and write code, pull requests, issues and commits |
| workflow | View and modify GitHub Actions workflows |
| read:org | Access private organization repositories |
| read:user | User identification |
What you should avoid enabling unnecessarily: admin:org, delete_repo, admin:repo_hook, write:org, or other administrative scopes.
The idea is the same as with any other credential.
If a token is compromised, it should only be able to perform the exact operations you intended.
The more permissions it has, the larger the blast radius.
If your use case supports them, fine-grained tokens are usually a better option because they allow you to restrict access to specific repositories instead of granting access to the entire account.
The same principle applies to every other kind of token or key.
Use 1Password CLI as the source of truth
One option is to use 1Password.
It provides a CLI that can inject secrets directly into your shell environment without requiring you to store the actual values in your configuration files.
Once everything is configured correctly, you will see something similar when Claude needs access to a specific item.
Install the CLI:
brew install 1password-cli
Check the account status:
op account list
If you use SSO, Okta or another identity provider, there is an additional consideration.
Create the item in 1Password:
- Create a new item of type API Credential in the vault you use.
- Give it an easy-to-reference name, for example
GitHub PAT. - Store the token in the credential field.
- If your Business account uses SSO, standard CLI authentication may not work directly.
- Open the 1Password desktop application.
- Go to Settings → Developer → Connect with 1Password CLI.
- Enable it.
The CLI will then authenticate through the desktop application, which already has your SSO session.
No master password needs to be placed in scripts or configuration files.
Then update your .zshrc:
export GITHUB_PERSONAL_ACCESS_TOKEN=$(op read "op://MyVault/GitHub_PAT/credential" --no-newline)
export GITHUB_TOKEN=$GITHUB_PERSONAL_ACCESS_TOKEN
Verify the environment variable without printing the complete secret:
echo $GITHUB_TOKEN | cut -c1-4
# Reload the shell configuration
source ~/.zshrc
Before — the actual value can end up in .zsh_history, and Claude may be able to read it:
export GITHUB_TOKEN=ghp_abc123xyz…
Now — the value itself never appears directly in the configuration.
Claude only uses $GITHUB_TOKEN from the environment.
The actual secret stays in 1Password, and you never need to paste it into the chat.
The MCP configuration can then inherit the variable from the environment instead of hardcoding it:
"github": {
"type": "stdio",
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server"
],
"env": {}
}
Finally, verify that Claude can still operate correctly.
For example:
list my GitHub repositories
If the MCP server can still return your repositories, the flow works end to end.
Step 3.1: Rotate credentials
If a key has been exposed, even briefly, rotate it.
With AWS and GitHub this is usually quick, and rotating credentials reduces the amount of time an exposed key remains useful.
What this does not solve
If you paste a token directly into the chat, it is still sent to Anthropic.
1Password protects you from accidental exposure through configuration files or environment setup.
It does not protect you from secrets that you deliberately paste into a conversation.
The most important security control is still your own workflow and habits.
5. Beyond credentials: securing Claude Code itself
Managing secrets correctly is only part of the problem.
Claude Code also has a permissions and configuration system that is worth hardening.
5.1 Limit MCP servers
Do not enable every MCP server by default.
Only enable the ones you actually need and explicitly disable the others.
This can be configured in managed-settings.json:
"enabledMcpjsonServers": ["github"],
"disabledMcpjsonServers": ["filesystem"]
5.2 Configure permissions carefully
The remaining examples belong in settings.json.
Claude Code provides three permission levels:
- Allow — only for operations you consider completely harmless
-
Ask — operations with potential impact, such as
git pushordocker run - Deny — operations that should always be blocked
The important principle is the same: minimum privilege.
Before:
{
"permissions": {
"allow": [
"Bash(curl:*)",
"Bash(docker:*)"
]
}
}
After:
{
"permissions": {
"deny": [
"Bash(curl:*)",
"Bash(docker:*)"
]
}
}
5.3 Restrict access to sensitive directories
You can also explicitly deny access to paths and files that may contain sensitive information:
{
"permissions": {
"deny": [
"Bash(curl:*)",
"Bash(rm -rf:*)",
"Read(~/.ssh/*)",
"Read(~/.aws/*)",
"Read(**/*.pem)",
"Read(**/.env*)"
]
}
}
5.4 Automatic cleanup
You can also configure cleanup of historical information:
{
"cleanupPeriodDays": 7
}
4. Lessons learned
Treat Claude Code like a junior developer with root access
Claude Code can dramatically improve productivity.
But if it is not configured properly, it can also:
- expose credentials;
- corrupt repositories;
- open the door to unauthorized access.
AI coding tools are extremely useful.
They should simply be treated with the same security discipline as any other tool that has access to your development environment.
Have you run into something similar? Do you use another approach for managing credentials securely? Let me know in the comments.

Top comments (0)