The setting is a single approval choice inside Claude Code: “Yes, and don’t ask again” on a proposed command. That click saves the approved command word for word, credentials included, in plain text. A sweep of public GitHub counted 104,185 copies of that file, and 1,379 real passwords and keys sat inside them. The uncomfortable part is not the count, and it surfaces two sections from now.
- How one approval writes a secret to disk
- What the count actually found
- Why your secret scanner misses this file
- The 10-minute check: the settings.local.json sweep
How one approval writes a secret to disk
Short answer first: Claude Code stores permanent approvals as allow rules inside .claude/settings.local.json, a per-project settings file. Any credential typed inside an approved command is stored with it, character for character. Claude Code asks before running most shell commands, several times in any working session. A database command often carries its password inline, behind a variable such as PGPASSWORD. Approve that command once, permanently, and the password joins your project’s configuration file. Claude Code adds the file to your machine’s global git excludes on first write, but that exclude lives on one machine and does nothing for clones, containers, or older commits. Agent tooling keeps failing this way, as The malicious Claude Code extension lasted 11 hours. A one-day install delay would have skipped it showed last month.
What the count actually found
The sweep read public repositories from November 1 to November 3, 2026, using GitHub code search. It collected 104,185 copies of settings.local.json across 103,617 public repositories. Exactly 1,122 copies, about 1.1%, held at least one credential. Those files held 1,379 distinct secrets: 636 provider keys and 743 passwords or tokens for public hosts. Database passwords formed the largest single group at 379, followed by 122 Supabase service-role keys. Another 734 secrets existed only in older commits, and 211 forks carried copies. The full figures sit in the complete findings behind this count. One honest limit matters: the researchers tested no credential and contacted no host. Every count therefore means credible, not confirmed live, judged by format and pairing with a public host. One notified organisation confirmed its exposed key was live.
Why your secret scanner misses this file
Here is the held-back detail: the standard secret scanners missed one file in five. Gitleaks flagged 564 of the 1,122 files; TruffleHog flagged 643. Neither tool flagged 215 files holding real secrets in plain text. Scanners pattern-match known key shapes, and a password typed inside a command has no fixed shape. A clean scanner report on this file therefore proves almost nothing about the file’s actual contents. Your exposure turns on settings files, just as The AI training opt-out is one robots.txt line now. Most Canadian sites we checked name no AI crawler decides crawler access.
The 10-minute check: the settings.local.json sweep
Run four steps in every repository where your team uses Claude Code. First, run git ls-files | grep settings.local.json to learn whether git tracks the file. Second, run git log --all --oneline -- .claude/settings.local.json to check whether history ever held it. Third, open the file and read every allow rule, hunting PGPASSWORD, sshpass, mysql -p, and bearer headers. Fourth, search your whole GitHub organisation with path:.claude/settings.local.json for every other repository. If any step hits, rotate those credentials at the issuer before you touch the file itself. Deleting the file changes nothing in history, forks, or clones; rotation comes first. Rotation-first is also the lesson of Railway paused deploys mid-breach. Rotate API keys at the issuer first. One plain note: no hands-on test ran for this piece; the sweep runs on your machines. Close this tab, open a terminal, and run the settings.local.json sweep on every repository your team touches.