---
id: 2026-11-claude-code-settings-local-json-standing-approval-stores-approved-commands-with-secrets-1122-public-github-copies
title: "Claude Code \"don't ask again\" writes approved commands, secrets included, to .claude/settings.local.json; 1,122 public GitHub copies hold secrets (Apiiro)"
date_disclosed: 2026-11-06
last_updated: 2026-11-07
severity: high
status: active
ecosystems: [claude-code, github, git, secrets, anthropic]
tools_affected: ["Claude Code (terminal, VS Code and JetBrains extensions, desktop app) in any git repository where a user chose \"Yes, and don't ask again\" for a Bash command that contained a password, token or key", "every public or shared repository that has committed .claude/settings.local.json or .claude/settings.json, including its history and forks", "secret scanners that do not inspect JSON allow rules (Apiiro says gitleaks flagged 564 and TruffleHog 643 of the 1,122 files)"]
tags: [credential-exposure, secrets-in-git, claude-code, settings-local-json, permission-rules, agent-config-files, rotate-credentials, vendor-no-response, the-hacker-news-front-page]
---

## TL;DR
When a Claude Code user answers a Bash permission prompt with "Yes, and don't ask again", Claude Code saves an `allow` rule for that command to `.claude/settings.local.json` at the repository root, and when the saved rule is the exact command rather than a prefix pattern, any password, token or key typed into that command is stored in the file in clear text. Apiiro reported on 2026-11-06, as relayed by The Hacker News on 2026-11-07, that 1,122 public copies of that file on GitHub hold at least one secret (1,379 distinct secrets, among them 379 database passwords, 42 GitHub, GitLab and npm tokens and 23 AWS keys), that one notified company confirmed its key was live, and that every such file was still on its repository's default branch as of 2026-11-02. Claude Code keeps the file out of commits through the user's global git excludes, not the repository's `.gitignore`, so a clone on another machine, a hand-created file, or a different git setup commits it. If your repository has ever contained the file, rotate every credential it held, then untrack it.

## What happened

**The mechanism, from the vendor's documentation.** Claude Code's settings page says Claude Code writes `.claude/settings.local.json` "the first time you give a standing approval on a permission prompt, such as 'Yes, and don't ask again' for a Bash command", and: "When Claude asks permission to run a Bash command and you choose 'Yes, and don't ask again', Claude Code saves that permission approval here as an `allow` rule." The permissions page says a Bash approval saved this way lasts "Permanently per repository and command", that "The permission dialog writes the space-separated form when you select 'Yes, and don't ask again' for a command prefix", and that for a compound command "Claude Code saves a separate rule for each subcommand that requires approval". A rule saved for an exact command is the command string inside `Bash(...)`. The docs on keeping the file out of git: "The first time Claude Code writes the file in a git repository that doesn't already ignore it, it adds `**/.claude/settings.local.json` to your global git excludes file, so the file stays out of your commits in every repository. That file is `core.excludesFile` when your global git config sets it to an absolute or `~`-prefixed path; otherwise it's `$XDG_CONFIG_HOME/git/ignore`, or `~/.config/git/ignore` when `XDG_CONFIG_HOME` is unset. If you created the file by hand and Claude Code hasn't written to it yet, add it to `.gitignore` yourself." Nothing in either page says the saved rule is redacted, and the exclusion is a per-machine setting, not a repository one. The docs also say the file's `allow` rules apply "without the workspace trust step" while the file stays untracked, which is why a tracked copy changes behaviour as well as leaking.

**The researcher's census, as The Hacker News reports it.** Apiiro's post (listed under Sources as not opened: the page returned HTTP 403 to every route this sweep has, and the Wayback Machine's 2026-11-07 07:57 UTC snapshot was not readable through this session's proxy) is summarised by The Hacker News (Swati Khandelwal, 2026-11-07), which says Apiiro published "yesterday". The figures below are The Hacker News's account of Apiiro's numbers; none was re-counted here. 104,185 copies of `.claude/settings.local.json` across 103,617 public repositories; 1,122 copies (about 1.1 percent) contain at least one secret; those hold 1,379 distinct secrets, including 379 database passwords, 43 SSH logins for public servers, 42 tokens for GitHub, GitLab and npm, and 23 AWS keys; 63 organizations own affected files; older versions add 734 secrets across 509 repositories; forks of 74 repositories carry the same secrets in 211 forks; of 76,011 copies of the shared `.claude/settings.json`, 298 contain secrets; across all sources, 2,539 secrets in 1,994 repositories. In 539 of 1,105 traced repositories, a commit listing Claude as a co-author changed the file. In half of the affected repositories the file had been present for at least 217 days. Gitleaks flagged 564 of the 1,122 files and TruffleHog 643, with 215 missed by both. Apiiro says it reproduced the behaviour with Opus 5.5 and Fable 5.1 and that, of 16 coding agents compared, "Claude Code is the only one confirmed to save the full approved command in a project file by default"; the comparison table is in the unopened post. Apiiro did not test whether the secrets still work; the one company it notified "earlier this week" confirmed its key had been live. "As of Monday" (2026-11-02), every file containing a secret was still on its repository's default branch.

**The reports the vendor's tracker closed.** The Hacker News says Apiiro cites a bug report filed 2025-08-11 that an automated bot closed as "not planned" on 2026-01-03 after 60 days of inactivity, and four related reports all closed by the same bot, the most recent "yesterday", none with a reply from Anthropic. GitHub's issue search (read 2026-11-07 through the API, titles and dates only) shows `anthropics/claude-code` issue #5544, "[BUG] approved bash commands containing credentials are stored as is with plain text credentials in settings.local.json", opened 2025-08-11 and closed 2026-01-03, which matches the dates The Hacker News gives. A later issue on the wider shape is still open: #95680 (2026-09-20), "Secrets that enter through the model's own tool calls fan out to every on-disk store, unredacted, and there is no way to find or scrub them". Neither issue body was opened this run.

**What the vendor has said.** Nothing that this sweep could find. The Hacker News reports no Anthropic response, the issues it cites carry none, and the documentation pages read on 2026-11-07 describe the behaviour without a warning about secrets in approved commands. The CHANGELOG through 2.1.319 (published 2026-11-06) carries no entry about redacting or refusing to save a rule that holds a credential. The adjacent control that does exist is in the opposite direction: the docs recommend `permissions.deny` rules such as `Read(./.env)` to keep Claude away from files that hold secrets, which does nothing for a secret the user types into a command.

**Why this is wider than one file.** The same file carries the `allow` list that lets Claude Code run commands without asking, so a committed copy in a public repository also tells a reader which commands run unprompted there. The shared `.claude/settings.json` is designed to be committed, and Apiiro's 298 secret-holding copies of it are the cases where someone wrote a credential into a rule by hand or moved a rule from the local file. The [agent-config-file](2026-05-trapdoor-cross-ecosystem-stealer.md) and [agent-memory](2026-10-claude-mem-setup-uploads-30-days-of-agent-prompts-to-cmem-cloud-15-2-0.md) files in this corpus describe the `.claude/`, `.cursor/` and `.gemini/` folders as places where agents write what they were told; this is the case where what they were told was a password.

## Am I affected?

1. **Is the file tracked, now or ever?** In each repository:
   ```bash
   git ls-files | grep -E '(^|/)\.claude/settings(\.local)?\.json$'
   git log --all --diff-filter=A --format='%h %ad %s' --date=short -- '.claude/settings.local.json' '**/.claude/settings.local.json'
   ```
   A hit on the second command with no hit on the first means the file was committed and later removed; the history and any fork still carry it.
2. **Does any version hold a credential?** Read every version of the file's `permissions.allow` array, not only the current one:
   ```bash
   git log -p --all -- '.claude/settings.local.json' '**/.claude/settings.local.json' '.claude/settings.json' \
     | grep -E '^\+.*"(Bash|PowerShell)\(' \
     | grep -iE 'password|passwd|secret|token|api[_-]?key|bearer|://[^/ ]+:[^@ ]+@|AKIA|ghp_|glpat-|npm_'
   ```
   Then read the matching rules in full. A rule that holds a `mysql -p...`, `psql postgres://user:pass@`, `curl -H "Authorization: ..."`, `aws ... --secret-access-key`, `npm config set //registry.npmjs.org/:_authToken=` or `ssh user@host` with a password is a leaked credential.
3. **Is the global exclusion in place on this machine?** `git config --global --get core.excludesFile` and then `grep -n 'settings.local.json' <that file> ~/.config/git/ignore 2>/dev/null`. No line means the next commit after a `git add -A` includes the file. A fresh machine, a container, a CI runner or a colleague's clone has no such line until Claude Code writes the file there.
4. **Do forks exist?** For a public repository, the fork list on GitHub is where the secret lives after you delete it; Apiiro counted 211 forks carrying secrets from 74 repositories.
5. **Organization-wide.** Search your own organization's repositories for both paths, including history. The organization-level `.gitignore` template and the secret-scanning configuration are where the fix for the next repository lives.

## If you are affected

- **Rotate first, then clean up.** Change every password, token and key the file has ever held, in every version and every fork, before touching git history; the researcher's advice, and this corpus's, is in that order because deletion does not undo a public commit. Use [if your GitHub PAT leaked](../playbooks/if-your-github-pat-leaked.md) for GitHub tokens, [if your npm token leaked](../playbooks/if-your-npm-token-leaked.md) for npm tokens, and [rotating cloud credentials](../playbooks/rotating-cloud-credentials.md) for AWS keys and database passwords, which also covers checking the provider's access logs for use since the commit date.
- **Untrack the file.** `git rm --cached .claude/settings.local.json`, add `.claude/settings.local.json` to the repository's `.gitignore`, and commit. Rewriting history removes the bytes from your clone and your remote, not from forks, caches, or anyone who already pulled.
- **Scrub the rule locally too.** Delete any rule that contains a secret from the local file on every machine that has the clone, since the rule is still read and still applies, and from the shared `.claude/settings.json` if it was moved there.
- **Check who else loaded the rules.** A tracked copy of the local file applies its `allow` rules only after the workspace-trust step, per the docs, but a committed `.claude/settings.json` applies to every teammate who trusted the folder; a secret-bearing rule there lets Claude run that command without a prompt on every one of their machines, and the secret is in every clone.

## Prevention

- **Approve patterns, not commands.** When the prompt offers "don't ask again for: `npm test *`", that prefix form is what should be saved. A rule for an exact command that embeds a credential is the one that leaks; an exact command with a secret should be approved once, or rewritten to read the secret from the environment (`psql "$DATABASE_URL"`) before approval.
- **Keep secrets out of commands.** Give the agent `$VAR` references and a secrets manager, not literals. [Credential hygiene](../prevention/credential-hygiene.md) covers the shape.
- **Treat agent folders like `.env`.** Add `.claude/settings.local.json`, and the equivalents for other agents, to organization `.gitignore` templates; add `.claude/`, `.cursor/`, `.gemini/` and agent memory files to pre-commit and CI secret scanning, with history enabled; make sure the scanner inspects strings inside JSON arrays and shell commands, since Apiiro says the two common scanners each missed about half of the files. [CI/CD hardening](../prevention/ci-cd-hardening.md) has the pipeline side.
- **Audit existing repositories once.** The checks above take a minute per repository and the file has been shipping for over a year; Apiiro's median age for an affected file is 217 days.

## Sources

- [The Hacker News — Claude Code's "Don't Ask Again" File Exposes Passwords and Keys in 1,122 Public Copies on GitHub](https://thehackernews.com/2026/11/claude-codes-dont-ask-again-file.html) — fetched 2026-11-07: Swati Khandelwal, 2026-11-07; every count above; the 2025-08-11 report and the bot closures; "as of Monday"; the one confirmed live key; the sixteen-agent comparison claim; no Anthropic response reported; the remediation list.
- Apiiro — Coding agents leaking secrets on GitHub ("don't ask again") at `apiiro.com/blog/coding-agents-leaking-secrets-github-dont-ask-again` — **not opened**: HTTP 403 to `WebFetch` and to `curl` on 2026-11-07; the Wayback Machine's availability API reports a snapshot at 2026-11-07 07:57:12 UTC that this session's proxy could not retrieve. Every figure attributed to Apiiro above is The Hacker News's account of the post.
- [Claude Code docs — Settings files and precedence](https://code.claude.com/docs/en/settings.md) — fetched 2026-11-07: the local file's purpose, "the first time you give a standing approval", "saves that permission approval here as an `allow` rule", the global-excludes mechanism and its three candidate paths, "If you created the file by hand ... add it to `.gitignore` yourself", the trust-step difference between tracked and untracked copies, the `/permissions` destination note for VS Code.
- [Claude Code docs — Configure permissions](https://code.claude.com/docs/en/permissions.md) — fetched 2026-11-07: "Permanently per repository and command", the prefix form written for a command prefix, one rule per subcommand of a compound command, the file saved "at the root of the git repository".
- [anthropics/claude-code — issue #5544: approved bash commands containing credentials are stored as is with plain text credentials in settings.local.json](https://github.com/anthropics/claude-code/issues/5544) — read 2026-11-07 through GitHub's issue search API, title and dates only: opened 2025-08-11, closed 2026-01-03; the body and comments were not opened.
- [anthropics/claude-code — issue #95680: Secrets that enter through the model's own tool calls fan out to every on-disk store, unredacted](https://github.com/anthropics/claude-code/issues/95680) — read 2026-11-07 the same way: opened 2026-09-20, open; body not opened.
- [anthropics/claude-code — CHANGELOG.md](https://raw.githubusercontent.com/anthropics/claude-code/main/CHANGELOG.md) — fetched 2026-11-07: no entry through 2.1.319 (2026-11-06) about rules that hold credentials.
- Related in this corpus: [Claude Code account email injected into model context](2026-10-claude-code-account-email-injected-into-model-context-leaks-to-git-headers-websites-issue-81138.md) (the other case this month where a Claude Code on-disk store carried something the user did not mean to publish, with the same bot-closed-issue history), [TrapDoor agent-config poisoning](2026-05-trapdoor-cross-ecosystem-stealer.md) (the `.claude/` folder as an attack surface in the other direction).
