Secret sprawl on developer machines: an audit guide

Ask any team how many secrets live on a typical developer laptop and you’ll get an estimate that is off by an order of magnitude. The one or two keys in ~/.bashrc are easy to account for. Everything else is not: the AWS credential in ~/.aws/credentials, the GitHub token in ~/.gitconfig’s credential helper, a dozen .env files scattered across cloned repos, the Stripe test key in a scratch file, the Docker config with a registry password, the npm token in ~/.npmrc. Secrets accumulate on developer machines the way dust accumulates on a bookshelf — silently, and in every crack.

Why sprawl is a real problem

Each copy of a secret is an attack surface. Malware on one laptop, a stolen device, an AI coding agent that reads dotfiles while answering a question, a curl command that dumps shell history — any of these exposes every secret that machine holds. Sprawl also breaks rotation: when a key is compromised, you cannot rotate what you cannot enumerate. The team rotates the key in the vault, and the copy in ~/scratch/notes.md from 2023 keeps working.

An audit is the first step, and you don’t need fancy tooling to start.

Where secrets actually live

Shell and profile files. ~/.bashrc, ~/.zshrc, ~/.profile, and the history files (~/.bash_history, ~/.zsh_history) are full of export TOKEN=... lines and pasted commands. Grep for export .*= and for known key prefixes.

Dotfiles and tool configs. ~/.gitconfig (credential helpers, sometimes plaintext tokens), ~/.npmrc, ~/.docker/config.json (registry auth, base64-encoded), ~/.aws/credentials, ~/.config/gh/hosts.yml (a GitHub token in plaintext), ~/.netrc, ~/.pgpass. SSH keys with empty passphrases deserve particular scrutiny.

Project files. .env files everywhere — and .env.example files that someone filled in with real values. Config files committed to repositories, editor settings, and VS Code tasks.json entries that embed tokens for build steps.

Caches and logs. Shell history, editor swap files, ~/.cache/ directories, application logs. These are the ones people forget, and the ones most likely to be read by tooling.

Running the audit

  1. Enumerate. Walk the home directory for the files above. find ~ -name '.env*' -o -name '*.npmrc' gives you a list fast.
  2. Scan with pattern tools. Run a secrets scanner with plain-file support over the whole home directory. High-entropy detection flags long random strings; triage the hits by hand.
  3. Check the git-history angle. Every cloned repo on the disk carries its own history, including deleted files. Your machine is a museum of everyone’s old secrets.
  4. Write it down. Keep a per-machine inventory: secret name, location, whether it’s still valid, and a rotation date. You can’t manage what you haven’t listed.

Reducing sprawl at the source

The audit finds the mess; process changes stop it from coming back. Rules that work in practice:

  • Centralize. Keep secrets in a password store (the pass tool is the common default) or a vault, and never paste values into files.
  • Inject, don’t copy. Runtime injection — a tool that reads the store and sets environment variables for a subprocess — means the value exists in memory for the duration of a command, not in a file on disk.
  • Give agents a broker. AI coding agents are a new and prolific source of sprawl: they write config files, persist context, and copy values into logs. A credential broker that injects secrets only into the commands they run keeps keys out of their context windows and session files.

That last point is what trustless is: a zero-dependency, single-binary credential broker CLI that reads your existing pass or Bitwarden store, injects secrets into subprocess environments, and sanitizes output, with an append-only audit log of every injection. Its trustless doctor command checks GPG validity, pass health, and scans for stray .env files — a reasonable first pass for the audit step too.

After your next audit, how many of the secrets you found were ones you had forgotten existed — and how many are still in rotation today?