A permission button meant to stop Claude Code interrupting you saved whole shell commands, credentials included, as allowlist rules. Apiiro went looking for the resulting files in public repositories and found far more than the secret scanners had flagged.
What the Claude Code secrets leak actually is
The button is easy to like. A command shows up, you read it, it looks fine, and you click "Yes, and don't ask again" so the agent stops asking. What Claude Code does next is the part most people never see: it writes the approved command into .claude/settings.local.json as an allowlist rule, word for word.
Word for word includes the password. A database migration run as PGPASSWORD=... psql ... gets stored with the password still inside the string. So does an sshpass -p login, and so does a mysql -p call typed into a deploy script at two in the morning. The result is plaintext JSON sitting in a project directory.
Apiiro published its write-up on November 5. The finding isn't that a coding tool stores settings. It's that the settings it stores are credential material, and that this particular file has a habit of leaving the machine it was created on.
Apiiro Claude Code research: what the sample contained
Apiiro scanned 104,185 public copies of that settings file, pulled from 103,617 repositories. Of those copies, 1,122 held 1,379 distinct secrets. That's the narrow sample, and it's the number to quote when someone asks how many files were affected.
The wider sweep added shared settings files, agent transcripts and git history. It turned up 2,539 distinct secrets across 1,994 public repositories, touching 63 organizations. Two counts, two different things: files and secrets.
The mix explains why this isn't only an API key story.
Credential type | Count |
|---|---|
Provider-format API keys | 636 |
Passwords and tokens tied to public hosts | 743 |
Database passwords (inside the 743) | 379 |
Supabase service-role keys | 122 |
Supabase account tokens | 103 |
SSH credentials | 43 |
AWS keys | 23 |
Private keys | 6 |
Database passwords outnumber provider keys. A password for a hosted Postgres or MySQL instance is often the keys to the whole application, not to one API call. Some of the SSH entries were root logins wrapped inside sshpass commands, which is the worst thing on the list to leave in a file that gets committed.
Why the settings.local.json file travels further than it should
Claude Code isn't careless here in the obvious way. When it creates the settings file inside a repository, it adds that path to your global git ignore list. On your machine, in your repo, the file stays out of git.
Then the project moves. Someone zips the folder to debug a build, and a contractor clones a template that already contains the file. A fork copies it into a new repository. Apiiro measured that last path: forks carried credentials from 74 repositories into 211 additional copies.
Deleting the file now doesn't undo the earlier commits either. Old versions of these files held 734 secrets that no longer appear in current copies. The credential is still in the history, and history is what a scraper reads.
Claude Code credentials that no scanner recognizes
Both major open source scanners found plenty. Gitleaks flagged 564 of the 1,122 secret-bearing files, and TruffleHog flagged 643. Neither one flagged 215 of them.
The reason is structural. Detection rules key off provider prefixes: AKIA for AWS, sk- for a handful of API vendors, ghp_ for GitHub. A password written as PGPASSWORD=hunter2 has no prefix and no format to match. mysql -p is two tokens and a flag. An sshpass -p line is a shell command, so there's no odd format for a rule to catch.
So the tooling that would normally catch this at the commit hook has nothing to grip. That's not a knock on either scanner. It's a limit of pattern matching, and it means the file has to be caught before it reaches a commit.
One organization in the report confirmed that an exposed key had been live. Apiiro says it didn't test any of the credentials or contact the hosts involved, so "secret" here means credible credential material, not a login someone proved works.
What to do about the don't ask again Claude Code prompt this week
Rotate first. The order matters, because deleting a file does nothing about a key that has been public for months. Start with whatever the exposed commands touched: database users, Supabase service roles, SSH keys, cloud access keys.
Then untrack the file with git rm --cached .claude/settings.local.json, add a rule at the repository level so the next clone inherits it, and read the history for earlier commits. If the repository is public, treat every credential in those commits as burned. A public fork doesn't stop being public.
After that, fix the habit. Stop approving commands that carry a literal secret on the command line. Pass the value through an environment variable, then reference a secret manager such as 1Password or AWS Secrets Manager so the agent never sees the string it's about to run.
What the Claude Code finding means for every agent vendor
The mistake isn't Claude Code's alone. Any coding agent that remembers approvals, or logs the commands it ran, makes the same trade: convenience now, a plaintext copy of your credentials later. That isn't a reason to avoid agents. It's a reason to ask what they store.
One question is worth putting to whichever tool you use: when I approve a command, what gets written down, and where? If the answer includes the full command string, the file needs the same care you'd give a .env sitting in a public gist.
Watch whether this setting gains a redaction step, and whether the scanners add rules for inline password flags.
Cheap fixes.
Whether anyone ships them is the part still open.






