Jorge Turbica / blog · Blog ← All articles ES · Leer en español
AI

Claude Code's 'don't ask again' left 1,379 secrets in 1,122 public GitHub files

Claude Code saves approved commands, passwords included, in settings.local.json. Apiiro found 1,122 public copies with secrets; scanners missed 215.

Out of 104,185 public copies of .claude/settings.local.json on GitHub, 1,122 hold at least one real secret: 1,379 distinct credentials, mostly database passwords. Apiiro published the numbers on November 5, 2026, and the root cause isn't a model failure but a very convenient button: "Yes, and don't ask again".

How a password ends up in a public repo

When Claude Code asks for permission to run a Bash command and you pick that option, it stores the approved command as an allow rule in .claude/settings.local.json at the repository root. If the command was PGPASSWORD=... psql -h db.example.com or sshpass -p ... ssh root@..., the password is saved verbatim in the rule.

According to Claude Code's documentation, the file should never reach git: the first time it writes it, it adds **/.claude/settings.local.json to your global git excludes. That's a real safeguard, but it lives on your machine, not in the project. A teammate without that exclusion, a hand-created file, a git add -f or a copied folder is all it takes for the file to land in a commit.

What Apiiro found

Researchers Shmulik Cohen and Matan Giladi collected the files from November 1 to 3, filtered out false positives and ran the masked candidates past an AI reviewer:

FindingCount
Public copies of settings.local.json checked104,185
Copies with at least one secret1,122
Distinct secrets in those copies1,379
Database passwords379
Supabase service-role keys122
SSH logins to public servers43
GitHub, GitLab and npm tokens42
AWS keys23
Total including history, shared settings.json and transcripts2,539 secrets in 1,994 repos

Git history makes it worse: there are 734 more secrets in older versions of the file across 509 repositories, and 211 forks of 74 repos carry the same values. Deleting the file today doesn't remove them.

In 539 of the 1,105 repositories Apiiro could trace, the file was changed by a commit with Claude listed as co-author. The report is careful to say this doesn't prove Claude introduced every credential, but it does show the agent will commit its own configuration when nothing stops it.

Apiiro didn't test the credentials, so it can't say how many still work. It identified 63 affected organizations, notified them on November 2 and 3, and at least one confirmed its key was live.

Why scanners miss it

Across the 1,122 files, Gitleaks flagged 564 and TruffleHog 643 (both run without their verification step). 215 slipped past both. Most were passwords inside a command, after PGPASSWORD=, sshpass -p or mysql -p: they lack the recognisable shape of an AWS key or a GitHub token, so to a scanner they're just text.

That's the figure that worries me most. Plenty of teams rely on repository secret scanning to catch any leak, and here one in five files sails cleanly past the two most popular open source tools.

Claude Code versus other agents

Apiiro compared 16 coding agents, and Claude Code is the only one confirmed to save the full approved command in a project file by default. The problem isn't new: issue #5544 described it in August 2025, and a bot closed it as "not planned" on January 3, 2026, after 60 days of inactivity.

In the Hacker News thread, Boris Cherny from the Claude Code team acknowledged the tool hasn't done secret scrubbing and said the team is looking at options. He recommends auto mode over piling up permission rules, and turning on secret scanning on your git host whatever agent you use.

What I'd do this week

  1. Check whether the file is tracked in your repos, history included:
bash
git ls-files '*.claude/settings.local.json'
git log --all --oneline -- '*.claude/settings.local.json'
  1. If it shows up, rotate any credential it ever held first. Deleting the file doesn't pull it from history, forks or clones.
  2. Stop tracking it and add the exclusion to the project's .gitignore, which does travel with the repo:
bash
git rm --cached .claude/settings.local.json
echo '.claude/settings.local.json' >> .gitignore
  1. Go through the file's allow rules by hand and delete any that contain literal values.

The caveat that matters: passing the password through an inline variable isn't enough. PGPASSWORD=s3cr3t psql … still puts the value in the command text that gets saved; what stays out is a reference resolved at run time, such as an already exported variable or a secrets manager.

Sources

Jorge Turbica

Software Engineer and SRE. I write about the real challenges I run into in production.

See portfolio ↗