Secret scanning
On this page
In plain terms
Secret scanning looks through your code, and its git history, for things that should never be
there: API keys, database passwords, private keys, cloud credentials, tokens. These get committed by
accident constantly (a quick test, a copy-paste, a config file that wasn't .gitignored), and once
they're in git history, they're effectively permanent.
Why it matters
A leaked cloud key can become someone else's crypto-mining bill, or a full breach, within minutes; bots scan public commits continuously. And "just delete it" doesn't work: git keeps every version, so a secret committed and then removed is still sitting in the history for anyone who clones the repo. Leaked credentials are one of the most common initial-access vectors in real breaches.
Where it fits
- Artifact: the repository. Both the current tree and its full history.
- Stage: ideally a pre-commit hook (stop it before it's ever committed), plus a CI gate and periodic history scans as a backstop.
How it works
Secret scanners combine two strategies: high-signal regular expressions for known token formats (AWS keys, GitHub tokens, Stripe keys all have recognizable shapes) and entropy analysis to catch high-randomness strings that look like generated secrets. Better tools reduce noise by validating format checksums and understanding common false positives (example keys in docs, test fixtures).
Popular & reputable tools
| Tool | Notes |
|---|---|
| Gitleaks | OSS, fast, scans tree + history; easy pre-commit hook |
| TruffleHog | OSS; notable for verifying found secrets against the live service |
| git-secrets | OSS, from AWS; lightweight pattern-based hook |
| GitHub Secret Scanning | Built into GitHub; partners auto-revoke leaked tokens |
Common pitfalls
- Finding it isn't fixing it. A detected secret must be rotated (revoked and reissued), not just deleted. Assume anything committed is already compromised.
- History is the hard part. Purging a secret from git history means rewriting it
(
git filter-repo) and force-pushing, disruptive, so prevention beats cleanup. - False positives from example values and test data need allow-listing to keep signal high.
secrets control runs Gitleaks over each component's repository and reports findings as SARIF. The two rows in the figure are the same descriptor with one line different, rather than two tools: history: true under gitleaks turns the per-change gate into the periodic deep sweep. Leaked credentials are treated as top-priority findings whatever the severity math says, because a live key is a live key.History findings are marked as such and carry the commit. A secret that has moved since it was committed is reported at the path it lives at now and the one it was introduced at, because those two call for different work: one is a file to change, the other is a history to rewrite.
Gitleaks does not read a file whose name contains an archive extension, such as
notes.zip.txt, so each one is listed under Caveats as unread, with that reason, rather than counted as clean. Rename the file, or fail the run on it with failOnCaveats: [unread-files] in the descriptor's gate.See the
gitleaks options in the Saga reference, and pair the control with a pre-commit hook to stop leaks before either row sees them.
Keep learning
- SAST, insecure code patterns beyond secrets
- Shift-left & DevSecOps, catching issues before they merge