1,122 GitHub Files Exposed Secrets—What Did “Don't Ask Again” Save?
Apiiro found credentials in 1,122 public Claude Code settings files. A saved approval can preserve the password inside a command—and send it into your next commit.
The approval became a credential store
Claude Code’s promise to stop interrupting you comes with a storage decision worth inspecting. Apiiro’s November 5 research reports that 1,122 public GitHub copies of .claude/settings.local.json contained credentials. The route: a command included a secret, the developer selected “Yes, and don’t ask again,” and the saved permission retained the command—including its sensitive contents. Someone then committed the file. Apiiro’s report turns a familiar convenience button into a concrete audit target for this week.
The researchers examined 104,185 public copies of that local settings file. Their wider investigation, including history and other agent artifacts, identified 2,539 distinct secrets across 1,994 repositories. Those are different populations: 1,122 is the number of affected local settings files, not the number of verified working passwords or compromised companies. Apiiro did not test credentials or contact their hosts; one organization confirmed that its exposed key had been live.
That distinction matters. Public credential exposure warrants action without evidence that someone used the credential. But an exposed string, a functioning credential and a confirmed intrusion are three separate claims. The report establishes a publication problem; it does not establish that every affected service was breached.
What the button remembers
The official permissions documentation says persistent approvals are saved to .claude/settings.local.json. For Bash commands, the documented “don’t ask again” behavior is permanent per repository and command. A saved approval can therefore outlast the terminal session in which you made it.
This creates two decisions inside one click. You are deciding whether an action may run, and whether a rule describing that action should remain available for future sessions. A command can be acceptable to execute while being unacceptable to preserve verbatim. A production database password is an obvious example: permission to connect is not permission to make another durable copy of the password.
The practical review question is therefore more precise than “Do I trust this command?” Ask what the approval option will retain. If the visible command contains an actual token, connection string or password, stop and change how it receives that value before choosing a persistent approval. Repeated confirmation prompts are annoying. Discovering that the workaround became a password notebook is worse.
The documentation also distinguishes approval types: file-modification approval lasts until session end, whereas certain Bash and web permissions persist. Treating every approval as having the same lifetime makes it easy to miss the consequential one. This is a permissions-interface problem as much as a repository-hygiene problem: the storage consequence deserves the same attention as the proposed action.
“Local” describes scope, not a vault
Claude Code’s settings reference distinguishes user settings in ~/.claude/settings.json, shared project settings in .claude/settings.json, and personal project overrides in .claude/settings.local.json. The shared file is intended to carry team configuration; the local file applies to an individual developer’s project setup.
The reference says Claude Code adds the local file to global Git excludes when it first writes it. It also tells developers who create the file manually to add it to .gitignore themselves. That is a useful default, but the word “local” still describes configuration scope. It does not turn JSON into encrypted storage or establish that no copy has entered version control.
For a team review, separate two questions: which settings should teammates receive, and which files contain sensitive values? A shared configuration file can be appropriate to commit while a particular entry inside it is inappropriate to publish. Conversely, a personal file can be harmless today but become sensitive after a later approval. Classify the contents as well as the filename.
A sensible repository convention is to explain the distinction where contributors will encounter it: in the setup instructions and the ignore rules they inherit. Otherwise, each new contributor has to infer the policy from a hidden directory. Configuration should make the intended sharing boundary obvious before someone stages a large batch of changes.
Check the repository before the next push
Start with an inventory, not a dramatic cleanup command. In each active checkout, git ls-files -- .claude/settings.local.json .claude/settings.json identifies whether those paths are tracked. Then inspect their contents locally. Avoid pasting the findings into a public issue, a shared chat or an AI troubleshooting session; that would create another distribution channel for the same value.
Read permission entries as stored commands. Look for authentication arguments, authorization headers and connection strings, rather than searching only for familiar key prefixes. Also ask who owns each credential and what it can access. A useful finding is “this entry contains the staging database account’s password,” not merely “the scanner found something.” Ownership is what makes remediation executable.
Check previous commits too. git log --all -- .claude/settings.local.json .claude/settings.json is a starting point for locating changes to those paths in the refs available in that checkout. It is not a complete inventory of remote copies. An empty current file does not answer whether an earlier version contained a credential.
For a tracked personal settings file, git rm --cached .claude/settings.local.json removes it from the index while retaining the working copy. Add the path to the repository’s .gitignore and inspect the staged diff before committing. This addresses future tracking; it does not invalidate a password already published or erase earlier commits.
Keep the review bounded and useful. Record affected credential owners and remediation status without recording the secret itself. If several repositories share the same credential, treat them as one credential incident with multiple exposure locations. Otherwise, separate teams can each “fix” a file while leaving the same access token usable elsewhere.
Rotate access before polishing history
GitHub’s sensitive-data removal guide puts revocation or rotation first. That changes whether an exposed credential can still grant access. Deleting a line changes what a reader sees in the current revision. These are different operations, and the access decision should lead.
GitHub also warns that history rewriting has consequences: commit hashes change, signatures can be lost, and collaborators’ older clones can reintroduce removed material. Copies may remain in forks, clones, cached views or pull-request references. A force-push is therefore not a reliable substitute for revoking a credential.
Once access is contained, decide whether additional history cleanup is justified and coordinate it with contributors. Follow GitHub’s documented procedure instead of improvising a rewrite during an active incident. The cleanup plan should account for other copies and the possibility of recontamination. GitHub notes that rotating the secret may itself be sufficient in some cases.
For the replacement credential, use the incident to reconsider scope. Does a routine development task need production access? Can the account be restricted to the database, environment or operation involved? Those are engineering decisions for the affected service, not properties an agent approval can supply. Removing unnecessary access reduces the consequence of the next mistake.
Then inspect how the task obtains its credentials. Prefer a workflow that supplies sensitive values at execution time without placing their literal contents in the saved command. Verify the resulting settings entry locally with a harmless test value. Do not assume a variable reference solves every downstream logging problem: inspect the artifact you intend to protect.
An old warning gets a public count
The mechanism was already described in Claude Code issue #5544, opened on August 11, 2025. The reporter said approved Bash commands retained plaintext credentials in permissions.allow and requested sanitization or exclusion of sensitive values. The issue is marked closed as not planned; its visible activity includes an automated duplicate notice. That is a user report and issue status, not evidence of a subsequent fix.
The fresh reason to act on November 8 is the publication count, not the age of that complaint. Apiiro also reports that 215 of the 1,122 affected files were flagged by neither Gitleaks nor TruffleHog. A clean result from a familiar scanner should therefore inform review without ending it. The saved command still deserves a human reading.
For builders, the useful policy is specific: persistent approvals must not become a place to retain credentials. Review the stored rule when granting lasting permission, keep personal settings out of commits, and assign an owner to exposed access immediately. None of that requires abandoning coding agents. It requires treating the files they produce as part of the software you are shipping.
For tool makers, the design question is equally concrete: can an approval remember the permission without remembering the password? A developer asking for fewer interruptions should not have to discover the storage format after publishing it. Any interface that saves execution details should make the retained data visible enough to review before it becomes durable.
Frequently asked questions
Were 1,122 working passwords confirmed?
No. Apiiro counted affected files containing credentials; it did not test them for access.
Does deleting the settings file resolve exposure?
No. Revoke or rotate exposed credentials first, then address tracking and historical copies.
Which files should I inspect first?
Start with .claude/settings.local.json and .claude/settings.json, including their available Git history.
Sources
> Want more like this?
Get the best AI insights delivered weekly.
By subscribing, you agree to our Privacy Policy. You can unsubscribe at any time.
> Related Articles
Claude Code Left Secrets in 1,122 GitHub Files—Check This Setting
Apiiro traced exposed credentials to Claude Code permission files. The awkward part: approving a command can preserve the password inside your project.
GPT-6 Cyber Can Build Exploits—But Builders Face a Different Test
OpenAI's GPT-6 Cyber pairs stronger exploit research with tighter scope controls. For builders, access rules and reproducible evidence matter as much as benchmarks.
GPT-6 Cyber Hits 48.5% on ExploitGym—Who Gets the Keys?
OpenAI’s GPT-6 Cyber pairs stronger exploit development with tighter scope controls. Builders face gated access, safety monitoring and a deployment job of their own.
Most Read
- 1 Kimi K3.1 Pro: China's Open-Weight Model Just Caught the Frontier
- 2 OpenAI Is Buying the Bottleneck: Can Orchestra Bio Cut a 15-Year Drug Timeline?
- 3 1,068 Tokens Per Second: Can Mercury 3 Change How LLMs Generate Text?
- 4 Same Price, Better Coding: How Good Is DeepSeek V4.1 Flash 1017?
- 5 Used OpenCode? Should You Rotate Your API Key After the Console Breach?
Latest News
- Claude Code Left Secrets in 1,122 GitHub Files—Check This Setting
- Gemini Omni 1.2 Flash Makes 15-Second Video Cheaper—Then Comes the Edit
- GPT-6 Cyber Can Build Exploits—But Builders Face a Different Test
- Gemini Omni 1.2 Flash Offers $1.05 Clips—What Does That Buy You?
- GPT-6 Cyber Hits 48.5% on ExploitGym—Who Gets the Keys?
- Docker Gives Coding Agents Their Own Kernel—What Happens to Your Files?
Tags
> Stay in the loop
Weekly AI tools & insights.