Sunday, November 8, 2026
AI

Claude Code 'Don't Ask Again' File Leaks Secrets on GitHub

Apiiro found 1,122 public Claude Code settings files holding 1,379 secrets, saved verbatim by the 'don't ask again' approval flow.

Illustration of a claw machine extracting keys from a folder-shaped glass box into a public space.
A convenience click quietly moves credentials from a private prompt into a public place.

More than a thousand public GitHub repositories are sitting on plaintext passwords, AWS keys and database credentials — not because anyone hardcoded them into source, but because developers clicked "Yes, and don't ask again" in Anthropic's Claude Code. The AI coding assistant saves approved commands verbatim into a project settings file, secrets and all. Security firm Apiiro said yesterday it found 1,122 public copies of that file holding at least one secret, according to The Hacker News.

The blast radius is not theoretical. The exposed files belong to 63 organizations, mostly software companies, and Apiiro's research write-up describes trophies including a database vendor's own admin-level cloud key and the owner password of a medical-records database. One company the researchers notified this week confirmed its key was still live. And here's the part that decides who owns the incident: deleting the file fixes nothing, because older versions persist in git history and in 211 forks. Rotation is the only remediation, and it belongs to whoever owns the repository — regardless of which employee, or which agent, committed the file.

The primitive: an allowlist that stores the whole command string

Walk the chain step by step, because the bug is boring and that's exactly why it scaled. By default, Claude Code asks permission before running most shell commands. If you pick "Yes, and don't ask again," it writes an allow rule into .claude/settings.local.json inside the project, per Anthropic's permissions documentation. Matching commands then run unattended in future sessions. That's the feature working as designed.

The failure is in what gets saved. The rule covers whatever the prompt offered — sometimes a pattern like npm test *, sometimes one exact command. When it's the exact command, any password or token you typed into it is persisted in plain text. Apiiro reproduced the behavior with the latest models, Opus 5.5 and Fable 5.1. One engineer in the Hacker News thread described hitting the same wall in the wild: approve curl -H "Authorization: Bearer sk-..." once, and the token lives in the settings file until someone happens to reread it.

{
"permissions": {
"allow": [
"Bash(PGPASSWORD=hunter2 psql -h db.example.com -U admin)"
]
}
}

Claude Code does try to keep the file out of git: the first time it writes the file in a repository, it adds it to the user's global git excludes, according to its settings documentation. But that's a per-user, per-machine ward. It does nothing for a file already committed, and Claude Code never adds the file to the project's own .gitignore — so the protection doesn't travel with the repo. Worse, in 539 of the 1,105 repositories Apiiro traced, a commit listing Claude as co-author modified the file, which the researchers read as the agent frequently committing its own secret-bearing config. A commenter on Hacker News identifying himself as a member of the Claude Code team argued the file is meant to stay local and that the team is looking into prevention; that's an unverified forum comment, but the mechanism it describes matches the documentation.

One convenience toggle, 2,539 secrets

Apiiro's scan of public GitHub turned up 104,185 copies of settings.local.json across 103,617 repositories. About 1.1% of them — 1,122 files — held at least one secret, 1,379 distinct secrets in total. A value counted as a secret when it matched a known key format or sat next to a public server's address, and an AI reviewer had to agree. More than a third open a database directly: 379 database passwords, plus 43 SSH logins for public servers, 42 tokens for GitHub, GitLab and npm, and 23 AWS keys.

The freshness numbers are the ugly part. As of Monday, every secret-bearing file was still on its repository's default branch, and in half of those repos it had been there for at least 217 days. Git history holds another 734 secrets across 509 repositories that no longer appear in any current copy — usually because someone deleted the file and called it done. Forks propagate the leak further: 211 forks of 74 repositories carry the same secrets as their upstreams. Add the shared .claude/settings.json file that teams commit deliberately (298 of 76,011 copies held secrets, mostly inside allow rules) plus older versions and saved agent chat logs, and Apiiro's total reaches 2,539 secrets across 1,994 repositories. Of 16 coding agents whose documentation the researchers compared, Claude Code is the only one confirmed to save the full approved command in a project file by default.

Two things remain unknown, and both matter. Apiiro did not test whether the secrets still work — the one live key came from a notified company's own confirmation. And the researchers don't say whether anyone has abused the exposed credentials. Treat both as open questions, not reassurances.

Illustration of endlessly branching folder corridors with light leaking from a few folders.
Git history and forks keep copies alive long after the original file is deleted.

Why gitleaks and TruffleHog walked right past it

If you're thinking your CI secret scanning already covers this — it probably doesn't. Apiiro ran gitleaks and TruffleHog, without their verification steps, over every file. Of the 1,122 with secrets, gitleaks flagged 564 and TruffleHog 643; neither caught 215. The misses are structural: scanners hunt known key formats, and a password trailing PGPASSWORD=, sshpass -p or mysql -p looks like an ordinary word in an ordinary command line. This is the same detection gap we've seen bite in adjacent tooling stories, from agents getting turned by a stray file to the trojanized Claude Code extension on Cursor's marketplace: the agent's working directory is a trust boundary nobody's monitoring.

Copies that never touch GitHub still count. The file is plain JSON in the project folder, which means it rides along inside npm packages, Docker images, zip archives and synced folders. And malware already shops this aisle: in September 2025, the Shai-Hulud worm ran the TruffleHog scanner over infected machines, and it flagged more than half the files it encountered as secrets. An uncommitted settings.local.json on a laptop is loot waiting for the next infostealer with a scraping rule.

Filed in August, closed by a bot

This wasn't a surprise to anyone watching the issue tracker. A bug report filed on August 11, 2025 described approved commands with API keys and tokens being stored word for word in settings.local.json. An automated bot closed it as "not planned" on January 3 after 60 days of inactivity. As of today, the researchers say, all four related reports they cite have been closed by the same bot — the most recent yesterday — and none received a reply from Anthropic. Anthropic has not publicly responded to Apiiro's findings as of this writing.

Who rotates, and what to audit this week

On liability, don't overthink it: the organization that owns the repository owns the rotation. It doesn't matter that an agent wrote the file, that a bot closed the ticket, or that the developer clicked a button the tool offered. The credential is yours, it's public, and the remediation order is fixed — rotate first, clean up second, because history and forks mean cleanup alone is cosmetic. Think of it as permadeath for secrets: there is no reload, only a new character.

Apiiro's developer-side checklist, condensed:

  • Search your GitHub organization for .claude/settings.local.json and .claude/settings.json, and grep each repository's git history for them — even where the files are long gone.
  • Rotate every password, token and key the files have ever held, before any cleanup.
  • Stop tracking the local file: git rm --cached .claude/settings.local.json, then add it to the repository's own .gitignore.
  • Open the file on your own machine even if it was never committed, and delete every rule containing a secret.
  • Keep secrets out of commands entirely — reference variables from a secrets manager, like $DB_URL, so the saved rule stores the variable name. Approve patterns such as Bash(npm run:*) instead of single commands.

For security teams, the researchers recommend treating agent folders — .claude/, .cursor/, .gemini/, .specstory/ — and agent memory files as secret-bearing, like .env, on laptops and in repos alike. Wire them into pre-commit and CI scanning including git history, with rules that catch passwords inside command lines rather than only known key formats. Add .claude/settings.local.json to organization .gitignore templates. And triage by reachability: credentials paired with a public server address go first, because those are the ones that actually open a door.

The editor's angle here is right, and the data backs it: this is a design failure wearing a user-error costume. A tool that persists approved commands verbatim, writes the result to a project file, protects that file only on the machine that created it, and sometimes commits the file itself has built a credential-exfiltration pipeline out of pure convenience. Sixty-three organizations are now doing incident response because of a button. Until the default changes, the allowlist is your attack surface — audit it like one.

Sources

This article draws on reporting and advisories from: