Currently Available: Need a skilled Software Developer for your next project?
Categories
Coding Agents

Where Claude Code Saves “Don’t Ask Again” Rules and How to Keep Secrets Out of Git

When Claude Code asks permission to run a command, choosing “Yes, and don’t ask again” saves a rule that lets Claude Code run that command without asking again. In a Git repository, Claude Code normally stores a persistent Bash approval in .claude/settings.local.json at the repository root. If the command contains a literal password, API key, or token, that text can end up in the saved rule.

Claude Code adds this local settings file to a machine-wide Git exclusion when it first writes the file in a repository. That tells Git on that machine to ignore the file when it is untracked. The exclusion does not travel with the repository. A repository-level .gitignore entry provides a shared safeguard. Neither kind of ignore rule removes a file already tracked by Git or protects a credential already committed.

Where Claude Code stores permission rules

Claude Code keeps settings at different scopes. The file path determines whether a setting belongs to one user, one project, or an organization. A persistent approval for a Bash command in a Git repository normally goes in .claude/settings.local.json; it does not automatically go in the user-wide settings file.

Settings file or scope Who it applies to Typical use
~/.claude/settings.json One user across projects on that machine Personal defaults and permission rules
.claude/settings.json Users of the project Settings intended to be shared and committed
.claude/settings.local.json One user in one project Personal project settings and persistent approvals
Managed settings Users covered by an organization’s policy Organization-defined settings

The Claude Code settings documentation describes these scopes and how settings files work. The permissions documentation explains that a standing Bash approval can apply to a repository and command. The root location is the normal behavior in a Git repository; documented exceptions include some non-Git and Windows cases.

Not every permission approval becomes a lasting rule. Claude Code documents different persistence behavior for different permission types. For example, file-edit approvals last only for the current session, while Bash approvals can persist. Use /permissions to inspect and manage rules; Claude Code shows which settings file each rule comes from.

What Git’s automatic exclusion does

When Claude Code first writes .claude/settings.local.json in a repository, it adds the pattern **/.claude/settings.local.json to the current machine’s global Git excludes. Git uses global excludes to ignore files for one user, outside the repository’s own .gitignore. core.excludesFile is a Git setting that names the global excludes file. Its location depends on the Git configuration.

That exclusion helps on the machine where Claude Code created it. A new workstation, container, or another developer’s clone does not inherit it. The repository’s .gitignore does travel with the project, so add this entry there as a second safeguard:

.claude/settings.local.json

This is especially important if someone creates the local settings file by hand. Claude Code’s settings documentation says manually created files should be added to .gitignore.

An ignore rule only tells Git to leave an untracked file out of future additions. It does not encrypt the file on disk, and it does not stop Git from tracking a file that was already added. To check the repository’s current state, run these commands from its root:

git ls-files .claude
git check-ignore -v .claude/settings.local.json
git log --all --oneline -- .claude/settings.local.json .claude/settings.json
git config --global core.excludesFile

The first command shows tracked files under .claude. The second reports which ignore rule applies, if any. The third checks available Git history for commits involving those settings files, and the fourth shows the configured global excludes file, if one is set. These checks help locate the files and rules. They do not replace a scan for credentials such as passwords or API keys, or a review of the file contents.

For a shared project, commit nonsecret settings in .claude/settings.json and keep personal approvals in .claude/settings.local.json. Review the proposed rule before granting permanent approval, and prefer a narrow rule that does not contain literal credentials. Environment variables or a secret manager can keep a credential out of command text, but the command and its handling still need review.

How command text can expose a credential

A saved permission rule can keep the text of the command. If a command includes a literal credential, such as a password embedded in a database connection command, the saved rule can preserve that value too. The risk concerns persistent rules containing sensitive command text; it does not mean every approval prompt is written to disk.

A reported analysis of public GitHub files found 1,122 files classified as containing at least one secret among 104,185 public copies of .claude/settings.local.json examined, or about 1.08% of that sample. The files contained 1,379 reported secrets. These figures describe the public files in the study, not all Claude Code users or private repositories. The researchers did not test every credential for validity, so the counts do not establish that every reported secret still worked or was misused.

What to do if Git tracked the file

If .claude/settings.local.json is tracked, adding it to .gitignore alone will not untrack it. After confirming that the repository should no longer include the file, remove it from Git’s index, the list of files Git tracks, while keeping the local copy:

git rm --cached .claude/settings.local.json

Then commit the removal and the .gitignore change. If the file contained a credential and was committed, treat that credential as compromised. Rotate or revoke it first; deleting the latest copy does not invalidate the credential or erase older versions.

GitHub recommends remediating a leaked secret by revoking or rotating it. Afterward, review relevant branches and commit history, along with other places the credential may have been copied. You can rewrite Git history to remove sensitive text, but coordinate with collaborators first: old clones and forks can retain the data, collaborators can reintroduce old commits, and rewritten commits receive new identifiers. GitHub’s guidance on removing sensitive repository data covers these trade-offs.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *