Dev.to · 4 min read

Apiiro’s Claude Code Scan Found 2,539 Secrets in .claude/settings.local.json — Local Desktop Tools Keep Credentials Off the Git Path

Apiiro’s Claude Code Scan Found 2,539 Secrets in .claude/settings.local.json — Local Desktop Tools Keep Credentials Off the Git Path

On 5 November 2026 Apiiro published a scan of public GitHub for Claude Code’s local settings files. They examined 104,185 copies of .claude/settings.local.json across 103,617 repositories. 1,122 of those files contained at least one secret (1,379 distinct values in the current copies). Expanding to git history, shared settings, and agent transcripts raised the total to 2,539 distinct secrets across 1,994 repositories and 63 organisations. The bulk were database passwords (379), plus SSH logins, cloud keys, and registry tokens. At least one company confirmed an exposed key was still live. The mechanism is simple. Claude Code asks for permission before running a shell command. Choosing “Yes, and don’t ask again” stores the exact command string as an allow rule in the local settings JSON. If that command contained a password or token (common when testing a connection string or API call), the secret is persisted in plain text. Claude Code adds the file to a gitignore when it creates it inside a repo, but that protection does not travel with forks, history, or copies that land outside the original tree. In 539 of the traced repositories a commit listing Claude as co-author touched the file. { "allow": [ { "command": "psql postgresql://user:SuperSecretPass@prod-db.example.com/app" } ] } That is the entire class of bug: an approval that was meant to be ephemeral becomes durable config, and durable config ends up in version control. Why this does not happen in a local desktop audio pipeline A Windows tool that captures microphone and loopback audio, runs local STT, and optionally posts a short translation or reply never needs to store a shell command that embeds a production credential. The hot path is: WASAPI capture (shared or exclusive) on the mic and on the render endpoint for loopback Local model inference (GGUF / MLX / ONNX) inside the process or a sibling process Overlay draw of the transcript No external API key is required for the core path. If the user wants a cloud STT fallback or a larger translation model, the key lives in the process memory or in a DPAPI-protected store that is never written next to source. It is never serialised into a JSON allow-list that a coding agent can later commit. The latency numbers make the local path attractive anyway. Recent Coval measurements put Soniox STT RT v5 at ~47 ms time-to-final segment and Qwen3-ASR 1.7B variants around 35 ms. Those numbers already assume the audio has left the capture device. On Windows the capture side still costs 20–40 ms of buffer + mix + communications-enhancement jitter in shared mode. Exclusive mode can drop that, but then you fight device exclusivity and the rest of the desktop. A local model that finishes inside the remaining budget keeps the whole pipeline under a couple of hundred milliseconds without ever shipping the audio or a key to a third party. Practical controls that survive an agent Never put credentials on the command line that an agent can approve. Use environment variables or a secrets manager that the agent is not allowed to read, and pass only the variable name. If you must approve a command, make the allow rule a pattern that cannot match a secret, or strip arguments before storage. Treat .claude/ (and every other agent config directory) as untrusted. Add it to a global gitignore and to pre-commit secret scanners. The per-repo ignore that Claude writes is not enough. Prefer tools whose credential boundary is the OS user profile or DPAPI rather than a file that lives next to source. A desktop STT/translation overlay that runs entirely locally has no settings.local.json equivalent for the user to accidentally commit. The same discipline applies when you build the overlay itself. The process that owns the WASAPI client and the model runtime should not write its runtime config next to any repository the user might open in an agent. Keep it under %LOCALAPPDATA% or an encrypted store. Measure the capture latency with IAudioClient::GetCurrentPadding and the model latency with a tight loop around the inference call; those two numbers are the only ones that matter for the user experience. Local models and local capture do not eliminate every class of risk, but they remove the specific failure mode Apiiro just documented at scale: an agent approval that turns a one-time secret into permanent public config. For real-time audio work on Windows that is a useful constraint to keep. I'm building Talkaside, a Windows app for job interviews and calls in another language. Drafted with AI assistance from this project's code and logs.

This is a summary aggregated from Dev.to. Read the complete article on the original site:

Read full article at Dev.to

More AI & Machine Learning News