Audit Claude Code's Approval File Before Secrets Reach GitHub
A command approval can outlive the command. If a coding agent remembers an approved command by saving it as a permission rule, a password typed directly into that command may be saved with it. The command may run once, b
A command approval can outlive the command. If a coding agent remembers an approved command by saving it as a permission rule, a password typed directly into that command may be saved with it. The command may run once, but its copy can remain in a project folder, a Git commit, a fork, or an agent transcript.
That is the important detail behind a recent report about Claude Code. Apiiro compared documentation for 16 coding agents and said Claude Code was the only one it confirmed writes the full approved command to a project file by default. The risk is not that clicking an approval button automatically publishes a credential. The risk is that a convenience setting can persist the full command, while the file's protection may depend on a machine-specific Git ignore rule that does not travel with the repository.
This is a useful moment to audit more than one file. The same underlying mistake can affect any workflow that records commands, prompts, transcripts, or handoff notes: putting a real secret directly into text that an agent may save.
This guide gives you a practical way to look for that pattern, decide what counts as exposure, and reduce the chance of repeating it. It is based on public research and product documentation, not on a claim that the affected tool was tested here or that every exposed credential remains valid.
What the report says, and what it does not
Apiiro reported finding 1,122 public GitHub files named .claude/settings.local.json that contained a secret, among 104,185 public copies it collected from November 1 to 3, 2026. Across the affected files, it classified 1,379 distinct credentials. Its broader analysis of files and Git history counted 2,539 secrets across 1,994 repositories. Apiiro said one organization confirmed that a key it found had been live, but the researchers did not test every credential. These are the vendor's reported findings, not an independently replicated census. Apiiro's research
The product behavior is documented: when you choose βYes, and don't ask againβ for a Bash command, Claude Code saves the approval as an allow rule in .claude/settings.local.json. The docs say Claude Code adds that path to the user's global Git excludes file when it first writes the file inside a repository. That helps on that machine. It is different from a repository-level .gitignore entry shared with every clone. Claude Code settings documentation
The distinction matters. A local ignore rule cannot prevent a teammate's fresh clone, a container, or a CI environment from seeing an already tracked file as an ordinary project file. And Git's ignore rules do not untrack a file that is already committed.
First principle: do not put secrets in commands
A shell command is plain text. It can appear in terminal history, process listings, logs, CI output, screenshots, chat transcripts, and approval records. Sending a command through an AI agent adds another possible place it may be retained.
Avoid commands like these:
psql "postgres://app:[email protected]/app"
curl -u "admin:REAL_PASSWORD" https://api.example.com/check
PGPASSWORD=REAL_PASSWORD psql -h db.example.com -U app
The safer direction is to keep the credential in a secret manager or environment variable and refer to the variable by name:
psql "$DATABASE_URL"
curl -u "admin:$API_PASSWORD" https://api.example.com/check
This is not a guarantee that the secret is protected everywhere. A badly configured shell, command trace, crash dump, or script could still expose it. But the command text no longer contains the credential itself, so a saved approval rule is less likely to preserve the raw value.
For repeated operations, put the workflow in a reviewed script that reads credentials from the environment or a secret manager. Approve a narrow, stable task such as a test command, rather than a one-off command containing a literal password. Keep the script's inputs and logs safe too.
Audit a repository in four passes
Run these checks from the repository root. They are deliberately read-only except for the optional remediation steps below.
1. Check the current working tree
git status --short
git check-ignore -v .claude/settings.local.json
The first command shows tracked changes and untracked files that could be swept into a broad git add .. The second shows which ignore rule, if any, currently matches the local settings file. No output from git check-ignore means the path is not ignored by the active rules.
Check the repository's own ignore file too:
grep -nF '.claude/settings.local.json' .gitignore 2>/dev/null || true
A global ignore entry may make a local check look safe while the repository itself contains no protection for collaborators. Add the path to the repository's .gitignore even if you also rely on a global exclusion.
2. Check whether Git tracks the file now
git ls-files --error-unmatch .claude/settings.local.json
If Git prints the filename, the file is tracked. An ignore rule added afterward will not remove it from the index. If it reports that the path is not in the index, that only answers the current-tree question; the file may still exist in old commits.
Also look for related agent files, adapting the list to the tools your team uses:
find . -type f \( \
-path '*/.claude/settings.local.json' -o \
-path '*/.claude/settings.json' -o \
-path '*/.cursor/*' -o \
-path '*/.gemini/*' -o \
-path '*/.specstory/*' \
\) -not -path '*/node_modules/*' -print
Do not assume every matching file contains a secret. Treat the results as an inventory to review. Agent configuration can contain harmless preferences, but it can also preserve command arguments, tokens, or service URLs.
3. Check all reachable Git history
git log --all --oneline -- .claude/settings.local.json
git log --all --name-only --pretty=format: | grep -E '(^|/)(\.claude|\.cursor|\.gemini|\.specstory)/' | sort -u
The first command lists commits that changed this exact file on refs available in your local clone. The second surfaces agent-related paths across history. A clean current directory does not prove a clean history: someone may have removed the file in a later commit.
For a focused review of old versions, inspect each relevant commit rather than dumping a whole history into logs or chat:
git show COMMIT_ID:.claude/settings.local.json
Replace COMMIT_ID with a commit from the history search. Do not paste unredacted output into an issue, chat, or AI prompt. If you find a credential, consider it exposed if the commit was pushed to a remote or shared with anyone.
These commands only inspect refs and history present in your clone. They do not search every remote, deleted fork, CI artifact, package archive, or teammate's copy. For an organization-wide check, search every relevant Git hosting organization and repository, and review other distribution paths such as published packages or container build contexts.
4. Search for command-shaped secrets, not only key-shaped strings
Many scanners are good at recognizing known token formats. A human-chosen database password embedded in PGPASSWORD=... or curl -u user:password may not have a distinctive provider prefix. Apiiro reported that Gitleaks and TruffleHog did not flag 215 of the 1,122 files it classified as containing secrets in its sample. That is a finding about this specific analysis, not proof that either scanner is generally ineffective. Apiiro's methodology and results
Review relevant agent files for patterns such as:
-
password=,token=,api_key=orsecret= -
PGPASSWORD=,mysql -p, orsshpass -p -
curl -u user:passwordorAuthorization: Bearer ... - Database URLs that include a username and password
- SSH commands containing a password or private-key material
A quick search can help triage, but it is not a complete detector:
grep -RniE 'PGPASSWORD=|sshpass[[:space:]]+-p|curl[^[:cntrl:]]+-u[[:space:]]|Authorization:[[:space:]]*Bearer|password=|token=' \
.claude .cursor .gemini .specstory 2>/dev/null
Review matches locally and redact before sharing. Expect false positives, and do not interpret no matches as proof of safety. Encoded, split, or differently named values can evade simple patterns.
If you find a real credential, rotate first
If a secret appeared in a file that was pushed, shared, or copied into an artifact, treat it as compromised. Remove or revoke it at the provider, issue a replacement, and check its access logs where available. Prioritize credentials that can reach a public host or production service.
Then stop tracking the file and add a repository-level ignore rule:
git rm --cached .claude/settings.local.json
printf '\n.claude/settings.local.json\n' >> .gitignore
git add .gitignore
git commit -m "Ignore local Claude Code settings"
git rm --cached removes the file from the next version of the repository but leaves the local copy on disk. This cleanup does not erase the old value from earlier commits, remote copies, forks, or clones. Rotate before history rewriting, because a rewrite is not a substitute for revocation. If you need to remove sensitive material from shared history, coordinate with repository owners and affected collaborators; rewriting history can disrupt their work.
Also inspect the local file and remove any secret-bearing approval rules. Deleting a rule prevents future reuse, but it does not undo exposure that already happened.
Make the audit part of your normal workflow
A one-time cleanup is useful, but the durable fix is to treat agent-generated files as part of the repository's secret surface.
- Add project-level ignores. Ignore local permission files and other private agent state in the repository, not only in one developer's global Git config.
- Scan agent directories. Include the files your tools actually create in pre-commit and CI secret scanning. Include history scans for repositories with previous exposures.
- Test for generic passwords. Check whether your scanning setup recognizes secrets inside shell commands and connection strings, not only vendor-formatted keys.
-
Review before staging. Use
git status --shortbeforegit add .orgit add -A. Prefer staging explicit paths when practical. - Use short-lived, least-privilege credentials. A token that can only access a test resource for a limited period creates a smaller incident than a permanent production credential.
- Keep credentials out of transcripts. Treat agent logs, exported conversations, memory files, and handoff notes as potentially sensitive if you have ever supplied a secret in a prompt or command.
- Document the recovery path. Developers should know who can revoke a credential, where to check access, and whom to notify if a secret reaches a public repository.
A checklist you can save
Before using an agent on a repository:
- [ ] The repository ignores local agent settings in its own
.gitignore. - [ ] Secrets are supplied through a secret manager or environment, not written literally into commands or prompts.
- [ ] Approval rules are scoped to repeatable, low-risk commands.
- [ ]
git statusis reviewed before broad staging. - [ ] Secret scanning covers agent configuration and history, including passwords embedded in commands.
- [ ] Exposed credentials can be revoked and rotated quickly.
If a file may already have been pushed:
- [ ] Rotate or revoke every credential it contained.
- [ ] Review access logs and identify affected repositories, forks, packages, and artifacts.
- [ ] Remove the file from the current tree and add a project-level ignore rule.
- [ ] Review Git history and coordinate any history cleanup after rotation.
- [ ] Check local agent logs and shared copies for the same value.
The core lesson is broader than any one coding assistant: persistent convenience features turn command text into configuration, and configuration can travel farther than the machine where it was created. Keep the secret out of the command, make local state explicitly local in the repository, and assume a credential needs rotation once it has crossed a trust boundary.
I write practical guides on developer tools, backend engineering, and AI security. Subscribe if you want more. Have you found sensitive values in agent settings or Git history? What check caught them? Save the checklist above for your next repository security review.
Sources
Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β full credit and traffic to the original publisher.