The short version: Security firm Apiiro scanned public GitHub for Claude Code's local permission file, .claude/settings.local.json, and found real, exploitable secrets sitting in plaintext in 1,122 copies. The cause isn't a breach of Anthropic's infrastructure — it's a feature working as designed. When a developer answers "Yes, and don't ask again" to a command that happens to contain a password or key, Claude Code saves that exact command as a standing approval rule, secret included, in a project file that looks like harmless config and routinely gets committed. Apiiro's wider count, including shared settings, repository history, and saved agent transcripts, reached 2,539 credentials across 1,994 repositories, and at least one notified organization confirmed its key was still live.
What Apiiro found
Apiiro, an application and software-supply-chain security vendor, searched public GitHub for the exact filename Claude Code uses to remember command approvals. The firm pulled 104,185 public copies of .claude/settings.local.json and classified 1,122 of them — about 1.1% — as holding at least one real secret. Widening the search to shared settings files, repository history, forks, and saved agent chat transcripts, the count grew to 2,539 real secrets across 1,994 public GitHub repositories.
The breakdown matters because this wasn't mostly throwaway test data. More than a third of the secrets Apiiro classified could open a database directly — 379 database passwords in total — alongside 43 SSH logins for public servers, 42 tokens for GitHub, GitLab, and npm, and 23 AWS keys. The most serious cases reportedly included a database vendor's own admin-level cloud key and an owner-level password for a medical-records database.
Apiiro was careful about what it could actually confirm: the firm did not attempt to use most of the credentials it found. But it did notify affected organizations where it could identify them, and at least one confirmed that the key Apiiro flagged was still live. Half of the affected repositories, according to the reporting, had kept the file on their default branch for at least 217 days — long enough for any automated GitHub code-search scraper to find it.
How a routine approval becomes a committed secret
Claude Code, Anthropic's terminal-based coding agent, asks permission before running most shell commands. That checkpoint exists for good reason: letting an autonomous agent execute arbitrary commands with zero human review is its own risk. But repeated prompts for the same type of command create approval fatigue, so Claude Code offers a shortcut: Yes, and don't ask again.
That shortcut has to remember something so it can skip the prompt next time. The mechanism is an allow rule written to .claude/settings.local.json in the project folder. The problem is what gets remembered: if the command a developer approved was a database client invocation with a password on the command line, or a curl call with an API key in the header, the whole string — secret included — is what gets written to disk as the "remembered" rule.
The file is meant to stay local. Claude Code's own settings documentation describes adding the file to a developer's global git-exclude configuration the first time it writes it in a given repository. But a global exclude only holds where nothing has already overridden it, and it does nothing once a developer runs a blanket git add, copies the file into a monorepo that doesn't inherit the exclude, or simply doesn't notice a dotfile sitting in a working tree. Apiiro also found that Claude itself, acting as a git co-author, was party to many of the commits that shipped the file: it traced Claude-coauthored commits touching the settings file in 539 of 1,105 repositories it examined.
This also isn't a problem Apiiro stumbled onto cold. A bug report describing the same plaintext-credential behavior was filed against Claude Code's public tracker in August 2025. It was later auto-closed as "not planned" after sitting idle — more than a year of runway during which the underlying behavior continued unchanged. A separate security write-up from the firm ironPeak described the identical pattern in early 2026.
1 · First report
A bug report describing plaintext credentials landing in settings.local.json was filed against Claude Code in August 2025 and eventually auto-closed without a fix.
2 · Independent confirmation
Security firm ironPeak separately documented a committed Claude settings file containing database passwords and API keys in early 2026.
3 · GitHub-wide scan
Apiiro searched public GitHub for the settings file itself, pulled over 100,000 public copies, and classified which ones carried real secrets.
4 · Disclosure and response
Apiiro published its findings this month; Anthropic's head of Claude Code acknowledged the gap publicly and said the team is evaluating fixes.
Anthropic's response
Boris Cherny, who leads Claude Code at Anthropic, responded directly in the public discussion that followed the report. He acknowledged that the product has not historically done secret scrubbing, and said the team is "looking into what we can do to prevent this." He also reiterated the design intent behind the file: it is, in his words, "meant to stay local."
That distinction is worth sitting with. "Meant to stay local" describes a convention, not a control. Nothing in git, GitHub, or a typical CI pipeline enforces that a dotfile never gets committed. It only takes one contributor without the global exclude configured, one monorepo tool that flattens exclusions, or one bot commit that checks in generated config, and the secret is public the moment the branch is pushed.
Why "don't paste secrets into approvals" isn't the real fix
The advice circulating since this report broke is sound as triage: don't type raw credentials into commands you ask an agent to run, reference them by variable name instead, rotate anything that already leaked, and add the file to an explicit .gitignore rather than relying on a global exclude. All of that helps. None of it addresses the structural issue.
The structural issue is that Claude Code was handed the real credential in the first place. A coding agent that executes shell commands on a developer's behalf doesn't need to see a literal API key or database password to do its job — it needs the command to succeed. Those are different requirements, and conflating them is what makes "don't ask again" dangerous. Once the agent has the actual secret string in front of it, every memory mechanism the agent has — permission files, transcripts, shared config — becomes a place that secret can end up. You can patch one file path. You can't patch every place an agent might decide to remember something.
This is the same failure mode that shows up whenever a credential gets handed to a process that doesn't strictly need to hold it: a CI runner with a production key sitting in its environment variables, a script with a copy-pasted token, or now, a coding agent with a database password baked into an approved command. KnoxCall's architecture is built around not making that handoff in the first place: API credentials are injected at the egress wire at call time, so the application process, the CI job, or the coding agent only ever works with a reference, never the live string. If there's no literal secret for Claude Code to approve, there's no literal secret for a "don't ask again" file to remember or a commit to leak. That's a narrower claim than "this would have stopped the incident" — it's specific to credentials that flow through a gateway, not to every password a developer might type directly into a terminal — but it's the honest shape of the fix this incident points to.
What to do if you use Claude Code
- Check whether
.claude/settings.local.jsonis tracked in your repository withgit ls-files, and check history even if the file is gone now withgit log --all --full-history -- .claude/settings.local.json. - If a secret shows up anywhere in that history, rotate it first. Deleting the file or rewriting history does not undo exposure in forks, clones, or search-engine caches that already indexed it.
- Add
.claude/settings.local.jsonto your project's explicit.gitignorerather than relying on Claude Code's automatic global git-exclude behavior, which doesn't survive every workflow. - Stop typing live secrets into commands you approve for an agent. Reference them through environment variables or a secrets manager so any saved rule records a variable name, not a value.
- Turn on secret scanning for your source host, and confirm it covers hidden directories and dotfiles — several reports on this incident noted that standard scanners miss this particular path by default.
The broader pattern
Claude Code is far from the only coding agent with a "remember this permission" feature, and fixing this one file path wouldn't fix the underlying habit of typing credentials directly into terminal commands. The same root cause — a live secret handed to something that merely needs to make a call, not hold a value — shows up across CI pipelines, browser extensions, and now AI coding assistants. Teams reviewing how they manage API keys across development, staging, and production should treat this as a prompt to check their own exposure, not a one-off incident to patch around. See our related coverage on AI gateway architecture and API security fundamentals for more on keeping live credentials out of processes that don't strictly need them.