The Quiet Responsibility
S2 · Nº 01

4 MINMisha Tryndiuk

The API key that sat exposed for three years (and the four places yours are sitting now)

It was committed on a Friday in a busy sprint. Removed the following Monday, everyone assumed. Three years later a security review found it in four places nobody had thought about.

The Friday

The story is so common it’s almost boring. Right up until it isn’t.

A developer tests an integration locally, hardcodes the API key “just to make it work”, and commits in a hurry. The mistake is caught on Monday. The key is removed, new commit, everyone breathes out.

Three years later we run a security review. The key is still valid. And it exists in four places.

The four places

1. The git history. The obvious one, which still surprises: deleting the key in a new commit removes it only from that commit onward. The history remembers everything. Every clone of the repo, on every laptop, every CI runner, every old backup, carries the key with it.

2. The fork. The repo had been forked internally for an experiment the following year. The experiment died. The fork lived on. With the full history.

3. The CI logs. A debug print from that same busy sprint had logged the config, key included. The logs were archived for three years. Searchable.

4. The chat. “Does it work for you with this key?” Pasted into a team channel back then. Chat archives forget nothing.

None of them were exotic. All of them were predictable. That’s the point: a leaked secret spreads along completely ordinary workflows, and “we removed it from the code” touches only one of the trails.

The rule most teams are missing

So there is only one correct response when a secret has been exposed, however briefly:

Rotate. Always. Immediately.

Not “remove it and assess”. Not “it was only there for an hour”. Rotate the key, invalidate the old one, and then clean up the trails. A secret that has been in a commit, a log, or a chat must be treated as compromised, because you can never prove otherwise.

It’s a rule that has to be agreed on before the accident, because in the moment everyone would rather believe it went fine. Put it in the security standards, as I wrote in Standards in practice (in Norwegian): security is not flexible.

The defenses (one afternoon to get started)

  • Secret scanning on the repo – block commits with key patterns before they reach the repo, not after. GitHub has push protection built in, free and on by default for what you yourself push to public repos. For private and internal repos it sits behind GitHub Secret Protection, billed per active committer, so check what you actually hold a license for before you assume it’s on.
  • Vault/Key Vault as the only source – the code references, never contains.
  • Pre-commit hooks locally – catch it before it reaches the history. gitleaks and trufflehog are the two established ones, both open source, both runnable as a pre-commit hook and as a CI step. That last part is the point: a hook an individual can skip with --no-verify is a recommendation. The same check in the pipeline is a control. Run them once across the whole history too; that’s where the findings are.
  • And practice rotation – a key you don’t dare rotate is a key you don’t control.

One warning about the cleanup: removing a key from the git history requires rewriting the history (git filter-repo), and even then it lives on in forks, in CI caches, and with everyone who has cloned. So the order is always rotate first, clean up after. A key that has been replaced does no damage even if it’s left lying around. A key that has only been deleted from the history is still valid.

The bill that never came

Our key never did any damage, as far as we know. That was luck, and luck is not a control.

Check the four places today: the history, the forks, the logs, the chat. Many who look find something. And it often still works: GitGuardian retested, in January 2026, credentials that had been valid in 2022, and more than 64 percent still were. Finding it yourself is far cheaper than having it reported to you.