Secrets

Applies to practices.no-secrets.

Covers practices.no-secrets.

Two separate places a credential leaks

Most people guard the first and forget the second.

The repository. Once a secret is committed it is in the history forever, and deleting it in a later commit changes nothing - the old commit is still there, still cloneable, still on every machine that ever pulled. The only real remedy is to rotate the credential.

The web root. This one is less obvious and more dangerous. Whatever the deploy filter does not exclude gets uploaded into a directory a web server serves. An environment file sitting next to index.php is fetchable over HTTPS by anyone who guesses the filename, and they are all guessable. A licence key has been served this way from a live site.

So there are two lists to maintain, not one: what git ignores, and what the deploy excludes. They are not the same list and neither implies the other.

What counts

More than passwords:

Host names and remote paths matter too. They are not secrets on their own, but published together they are a map.

The pattern

Verify, do not assume

# Is it in the history at all?
git log --all --full-history -- .env

# Is it being served?
curl -sI https://example.com/.env | head -1        # expect 403 or 404
curl -sI https://example.com/.env.example | head -1

Do not reason about whether a path is served. Request it.

When one does leak

Rotate first. Cleaning the repository is the second step and never the first - the moment a secret is exposed, it should be assumed compromised, and rewriting history does not un-clone anything. Then note it in the handover so nobody spends an afternoon later wondering why the key changed.