Secrets Detection: Finding Credentials in Code and History
Of all the things a static scanner can find, a hardcoded secret is the one with the shortest path to a breach. An access key in a repository is not a code-quality issue to be scheduled for a future sprint — it is a live credential, often with production reach, sitting in a place that is frequently more exposed than the systems it unlocks. And the moment it lands in git, removing it becomes much harder than adding it was.
Secrets detection scans code, configuration, and commit history for credentials that should never be there: cloud access keys, database passwords, API tokens, private keys, and OAuth secrets. It works through three complementary techniques, and the best tools combine all three.
- Pattern matching. Many credentials have recognisable structure — a known prefix, a fixed length, a checksum. High-signal patterns catch provider keys with few false positives.
- Entropy analysis. Random-looking high-entropy strings suggest a generated secret. This catches unknown token formats but is the main source of noise, flagging hashes, UUIDs, and test fixtures.
- Verification. The strongest tools actively check whether a candidate is live — making a read-only API call to confirm the key still authenticates. A verified secret is not a maybe; it is an incident.
History is the real attack surface
The instinct on finding a committed key is to delete the line and commit the fix. That leaves the secret intact in the repository's history, retrievable by anyone who can clone it, across every branch and tag. Git is an append-only ledger by design. Scanning must therefore cover the full history, not just the current tree — walking every commit on every branch — and remediation must assume the secret has already leaked.
# still there in commit 9f3c1a — deleting the line today did not remove this
Rotate first, then clean up
The correct order of operations is unambiguous. Rotate the credential at its source so the exposed value no longer works — this is the step that actually closes the exposure. Only then worry about scrubbing history, which is disruptive (it rewrites commit hashes and breaks everyone's clones) and, crucially, does nothing if a copy was already harvested. Treat a public exposure as compromised the instant it is found.
Catching them before they land
Detection at multiple layers keeps secrets out of history in the first place. Pre-commit hooks block a secret on the developer's machine before it is ever committed. Server-side and CI scanning catch what slips past. Provider-side push protection can reject a push containing a recognised key outright. Layer them, because each catches what the others miss, and a baseline or allow-list keeps known test fixtures from drowning the real signals.
- Scan history on onboarding. A one-time deep scan of every repo surfaces the secrets already sitting in old commits.
- Verify to prioritise. A live, verified key jumps the queue; an expired or test value can wait.
- Expand beyond source. Secrets hide in CI logs, container image layers, and build artefacts too — scan those, not just the repo.
A secret is only dangerous while it is valid, and only findable if you look everywhere it can hide. Scanning the working tree alone is looking under the streetlight. The credentials that hurt you are the ones committed, forgotten, and never discovered — which is exactly why the history is where the search has to start.
- Check whether your secret scanning walks full git history and every branch, or only the current working tree — a deleted-but-committed key is still in the history.
- For any secret already found in a repo, confirm the response was rotation, not just deleting the line.
A one-off history scan is a start; a verified, prioritised sweep across every repo, CI log, and image layer is what our assessment runs for you.