Security & Supply ChainAI CodingDeveloper Tools

After Clicking "Don't Ask Again": Why Nearly Half of Leaked Configs Were Committed to GitHub by Claude Code Itself

When we use Claude Code to connect to databases, log into servers, or call external APIs, a confirmation prompt regularly appears in the terminal. To avoid hitting Enter every single time, many people default to option 2: allow and don’t ask again. Inside the project folder sits a .claude/settings.local.json configuration file dedicated to recording local allow rules. Once you select that option, the tool remembers that you approved the database client, while also copying the entire command line you entered, complete with plaintext passwords and public IPs, verbatim into that file.

Security firm Apiiro recently published a scan report uncovering 2,539 valid secrets exposed through these configurations across 1,994 public repositories on GitHub. Many developers assume they have never manually pushed that configuration folder to a repository. Yet after tracing the commit histories, Apiiro found that nearly half of the leaked files were packaged and pushed to GitHub by Claude itself when developers asked it to commit their code.

How Does a One-Off Command Turn into a Password Book That Even Scanners Miss?

It all starts with small shortcuts taken for convenience. When you ask the AI to check data in an online test database or log into a remote machine to inspect logs, it often assembles a complete one-liner terminal command. To bypass interactive prompts, it stuffs the password directly into the command line in formats like PGPASSWORD=<plaintext_password> psql -h <public_host> or sshpass -p <plaintext_password> ssh root@<public_host>. The moment you click allow and don’t ask again, that entire string is written verbatim into the allowlist array inside .claude/settings.local.json. A file meant to store permission toggles quietly turns into a plaintext password book holding both the front-door key and the street address.

That password book has already spread across public repositories. The 1,994 repositories and 2,539 secrets mentioned earlier span commit histories, shared configurations, and several other surfaces; even looking strictly at the 104,185 .claude/settings.local.json files currently sitting on default branches on GitHub, 1,122 of them store plaintext credentials directly.

Those live files directly hold 1,379 valid credentials in total. They have been sitting publicly searchable on default branches for a median of 217 days.

Database passwords paired with public host addresses alone account for 379 of them, alongside 43 login passwords for public servers. The haul also includes 122 privileged Supabase service-role keys capable of bypassing all row-level security policies, 103 Supabase account tokens with control over every project under an account, and an assortment of cloud platform and third-party API keys.

Why couldn’t secret scanners stop these leaks, even when so many teams already have them installed? Researchers ran gitleaks and TruffleHog, the two most widely used open-source detection tools, against the files already confirmed to contain sensitive credentials. Surprisingly, both tools missed the same 215 files, a miss rate of 19.2%. Traditional scanners rely heavily on spotting garbled token strings with recognizable prefixes like sk- or ghp_. Once plaintext database passwords sit tucked inside ordinary command-line arguments, they look no more conspicuous to a scanner than everyday English words.

After clicking Don’t ask again, commands containing plaintext passwords and public addresses are written verbatim into the project configuration file and leaked upon commit

If the Official Response Claims It Is “Automatically Gitignored on Creation,” Why Did Claude Push Nearly Half of Them Itself?

After the report hit Hacker News on November 7, it sparked a wave of questions from developers. Claude Code team lead Boris Cherny stepped in that same day to explain that this local configuration file was designed strictly to stay on a single machine. He claimed that Claude Code automatically adds the file to gitignore when creating it, meaning the leaked files must have been manually created and checked into repositories by users.

Inspecting the package code of the Claude Code v2.1.299 client, however, reveals that the actual implementation does not match his account. Earlier versions did write the ignore rule into the repository’s own .gitignore file, which travels with the codebase. After users complained about the tool modifying project files, the team changed this policy in late 2025, a shift cited across multiple community bug reports for causing secret leaks. Today, when the client creates .claude/settings.local.json, it leaves the project’s .gitignore untouched and instead writes an entry to ~/.config/git/ignore, the global Git ignore list that exists only on the current machine.

This single-machine mechanism breaks down outright in two common scenarios. First, if you start using Claude inside a brand-new empty folder, click don’t ask again, and only run git init afterward to initialize the repository, the client detects no repository at the time and skips writing the ignore rule altogether. Second, even when the client does write the global ignore rule on your current computer, that rule stays on that machine alone; the moment you copy the project to another computer or move it into a container, the protection vanishes.

Similarly, when packaging software for release, packaging tools do not consult Git’s global ignore list. A package scan report published by security firm Lakera this April also found 428 publicly published npm packages that bundled this local configuration file directly inside, with 30 of those packages carrying valid secrets.

Even more damaging is how Claude Code handles commits. The client’s package code shows that even after .claude/settings.local.json enters Git’s tracked files list, the client detects that state, quietly logs an internal telemetry event without showing any warning to the user, and keeps appending new passwords to the file.

When the user finally asks Claude to commit code, the defense collapses completely. The official Git commit system prompt for Claude explicitly warns the model not to commit secret files such as .env or credentials.json, yet leaves out its own .claude/settings.local.json. As a result, among the 1,105 leaked repositories with traceable commit histories, 539 had their files pushed to GitHub by commits carrying the Co-Authored-By: Claude trailer when users asked Claude to commit code, accounting for 48.8%.

A Password Filter Already Ships Inside the Package—Why Does It Protect Only the Official Cloud and Not Your Local Disk?

At this point you might wonder: how hard could it really be to check a command for passwords before writing it to a file? In the Hacker News discussion, Boris Cherny explained that Claude Code has historically never performed secret scrubbing because plenty of off-the-shelf tools already exist on the market, adding that the team is exploring prototype solutions to prevent such leaks.

In reality, the community uncovered this exact pitfall 15 months ago. On August 11, 2025, a developer submitted a security vulnerability report with reproduction steps to the official Claude Code repository, pointing out that approved commands save plaintext passwords verbatim inside settings.local.json. Official engineers never replied; after sitting unanswered for nearly five months, an official bot marked the issue as not planned and closed it automatically at the start of 2026.

More surprising still, opening the cloud sync module inside the client package reveals a ready-made piece of password-filtering code sitting right there. It scans a user’s permissions.allow rules one by one, strips out any rule that looks like it contains a credential on the spot, and even has the user-facing notice text already written.

If that ready-made filtering code already ships inside the package, why do plaintext passwords still show up in local configuration files? Because this official filter only runs when a user enables an official cloud remote session and uploads local settings to Anthropic’s cloud servers. When a user clicks don’t ask again and writes the command into a local project folder, the program never calls that existing filter. Protecting official cloud servers while leaving users’ local repositories exposed puts a double standard inside the very same package.

In his response, Boris also advised community members to stop using allow rules and switch to auto mode, where a background AI classifier judges whether a command is dangerous. Yet a reader in the comments immediately pointed out that whenever auto mode’s background classifier encounters a sensitive command carrying passwords or connecting to an external server, it is designed not to decide on its own and falls back to a manual prompt asking you to confirm. Click allow permanently, and the password still gets written into the exact same file. Confronted with that loop, Boris could only concede on the spot that the reader made a good catch and that the team still needed to figure out another approach. Moreover, auto mode’s own blocking capability is far less reliable than advertised: an independent evaluation just updated in late October by the Hong Kong University of Science and Technology tested 128 everyday development tasks and found that when instructions leave operational scope ambiguous, auto mode failed to block 81.0% of dangerous actions.

A double standard inside the same package: passwords in permission rules are automatically filtered out when uploading to the official cloud, yet allowed straight through when written to a local repository

How Can You Audit Your Setup in 30 Seconds Today, and Pass Secrets Without Leaving a Trace?

Since we can rely neither on the tool’s built-in single-machine ignore feature nor on auto mode, we have to close the hole ourselves. Taking 30 seconds right now to do two things will make your repositories completely immune.

First, stop trusting single-machine global ignore rules and add .claude/ to every project’s own .gitignore file; if the project publishes packages, add it to .npmignore as well. You can also search your computer for existing .claude/settings.local.json files to check whether they hold any plaintext passwords you casually approved in the past.

Second, completely separate approving which command to run from what the password actually is. When having Claude Code connect to databases or log into servers, do not write plaintext passwords directly as literals in the command; use environment variable names instead, or use the 1Password CLI op run --env-file .env -- claude to inject secrets into memory at startup.

That way, even if you cut corners and click allow and don’t ask again 100 times, Claude Code will only write variable names like PGPASSWORD=$DB_PASSWORD psql -h <host_address> into .claude/settings.local.json. Even if that file ever gets pushed to GitHub, anyone who grabs it walks away with nothing more than an empty shell.