Secrets inventory

The project keeps one private list of every credential it depends on. This page describes how that list is built and kept honest. It names no credential, location or finding.

What each entry records

For every credential, the list says:

  • what it is, and what uses it;
  • where it is minted, and from which human account;
  • every known copy, and who or what can read each copy;
  • how to rotate it;
  • what a leak would cost, and separately what a loss would cost. The two differ: a leaked password exposes what it guards, while a lost encryption key strands everything it encrypted.

Two rules frame the list.

  • Names and locations only. A value never goes into the list, an issue, a commit or a command line. Commands are chosen to print names and metadata, and a value that has to move is piped on standard input rather than typed as an argument.
  • One list. Partial lists existed before it, and they disagreed. They now defer to it, and every other place that names secrets is checked against it.

How it stays current

A test in continuous integration holds the list to the code in both directions. It fails if the list contains anything shaped like a credential. It also fails if the code reads a secret-shaped environment variable that the list does not name: one whose name contains KEY, TOKEN, SECRET, PASSWORD or CREDENTIAL, or a database URL. So a new secret enters the list in the same change that introduces it.

Things that sit beside secrets or look like them, such as a public OAuth client identifier, go in a “not secrets” section with the reason, so the next reviewer does not have to decide each one again.

Where secrets hide

A first pass has to cover more than the obvious configuration file:

  • every place a value gets copied, not only the one the code reads. A hosting platform that keeps old revisions can keep a copy of every environment variable in each of them, and a training platform can keep job specifications indefinitely;
  • the operating-system user environment, which every process inherits, AI-agent sessions included. One environment dump in a session writes the values into its transcript;
  • key files on disk, and the login stores of command-line tools;
  • credentials the application keeps in its own database, and how each one is protected there;
  • the logins a new machine would need.

One secret can travel under several names. A database password can sit inside a connection string, bare in a second variable, and in the variable a client tool reads. So the list is organised by secret, not by variable.

The accounts behind the secrets

Every machine secret is minted from a human login. If that login is lost, the secret can no longer be rotated or revoked. So the list ends with those accounts and what each one controls. They belong in a password manager with their recovery codes, and the cloud owner’s second-factor recovery codes are the root of everything else on the list.

What the pass left alone

The pass that built the list read names and metadata only. Two checks need the values themselves: whether every copy of a secret holds the same value, and whether stray copies sit in logs or downloads. Those were left to someone who already holds the values, rather than loaded into an agent’s process.

Its findings are tracked privately.