Articles / Secrets Detection: Finding Credentials in Code and History
AppSec · Secrets Scanning

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.
live → incidentDeveloper commitskey in codeGit historyevery branch & tagScanpattern + entropyLive?verify credentialRotate at sourceDeleting the lineleaves the key inhistory — stillclonable
A committed secret's life — why history, not the working tree, is the attack surface.
Why it matters: Deleting a secret from the current code does nothing to the copies preserved in every prior commit. If it was ever pushed, assume it is compromised. The only safe response is rotation, not deletion.

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.

The secret survives the fixgit log -p --all | grep -i "aws_secret_access_key"
# 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.

Test for it — in practice
  • 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.

Keep reading
Software Composition Analysis and the SBOM