Hardcoded secrets are the most common credential exposure in software, and the numbers keep climbing. GitGuardian's annual research found that nearly 24 million new secrets were leaked to public GitHub repositories in 2024 — a figure that has grown every year, driven partly by AI coding assistants that happily complete a config file with a plausible-looking key. The problem is not that developers are careless; it is that a secret in code is invisible to the human eye in a diff of hundreds of lines, and git preserves it forever once committed. The Toyota T-Connect leak — a hardcoded access key public for nearly five years — and the Uber 2016 breach both started with a secret sitting in a repository that no one thought to scan. This guide covers how detection actually works and how to build it into the workflow so secrets are caught before they merge.
How hardcoded secrets get in
They arrive through ordinary developer convenience. Someone hardcodes a token to test an integration quickly and forgets to remove it. A .env file with real values gets committed because it was not in .gitignore. A config template ships with a placeholder that someone replaced with a real key. An AI assistant autocompletes a connection string with the actual password from an adjacent file. Copy-pasting from a working example into a committed test fixture drags a live credential along. None of these feel risky in the moment, and none are visible in a large diff — which is exactly why detection has to be automated rather than left to code review.
How secret detection works
Two techniques do the heavy lifting. Pattern matching uses regular expressions tuned to known credential formats — an AWS key starts with AKIA, a GitHub fine-grained token with github_pat_, a Stripe live key with sk_live_. These are precise for structured secrets but miss generic passwords. Entropy analysis measures the randomness of a string: a high-entropy 40-character blob is far more likely to be a secret than an English word, so it catches credentials that have no fixed prefix. The best scanners combine both and then add validation — actually checking whether a candidate credential is live — to cut false positives, because the biggest complaint about naive scanners is that they flag every example key and test fixture equally. Detection also has to run over history, not just the current tip, because a secret removed from the latest commit is still fully readable in earlier ones.
Building detection into the workflow, with commands
Scan the full history of a repository, not just the working tree:
# gitleaks: scan all commits, not just the current checkout
gitleaks detect --source . --log-opts="--all" --redact -v
# trufflehog: scan history and only report verified live secrets
trufflehog git file://. --only-verified
Block secrets before they are ever committed with a pre-commit hook:
# .pre-commit-config.yaml
# repos:
# - repo: https://github.com/gitleaks/gitleaks
# rev: v8.x
# hooks:
# - id: gitleaks
pre-commit install
pre-commit run --all-files
Fail the build in CI so nothing merges with a secret in it:
# Non-zero exit fails the pipeline stage when a secret is found
gitleaks detect --source . --redact --exit-code 1
Reduce noise by ignoring known-safe fixtures with an allowlist file rather than disabling the scan, so real findings are never buried under example keys.
Secret-detection checklist
| Practice | Why it matters |
|---|---|
| Combine pattern matching and entropy analysis | Catches both structured and generic secrets |
| Validate candidates against the provider | Cuts false positives from example and test keys |
| Scan full git history, not just HEAD | Secrets removed from the tip persist in old commits |
| Pre-commit hook on every developer machine | Stops the leak before it is ever pushed |
| CI gate that fails on findings | Prevents a merge that reintroduces a secret |
| Maintained allowlist for known fixtures | Keeps signal high so real findings are acted on |
| Rotate any secret a scan finds | Detection without rotation leaves the key live |
How Safeguard's secret scanning helps
A scanner that floods you with example keys gets muted, and a muted scanner catches nothing. Safeguard's secret scanning combines pattern and entropy detection across your repositories and full git history, then uses Griffin AI to validate which candidates are live credentials and rank them by provider and blast radius — so the queue shows real, exploitable secrets first instead of every high-entropy string. Developers catch leaks before they push by running the Safeguard CLI locally and in pre-commit, and the same scan gates CI so nothing merges with a live secret in it. Because secrets, vulnerable dependencies, and misconfigurations surface together in one software composition analysis view, you triage supply-chain risk from a single prioritized list. If you are comparing scanners, the Safeguard vs Snyk breakdown covers how validation and prioritization differ.
Bring continuous, validated secret and dependency scanning to every repository — get started free or read the documentation.
Frequently Asked Questions
Why not just review diffs carefully instead of running a scanner?
Because a secret is a few characters in a diff that can span hundreds of lines, and reviewers miss it reliably. The scale — nearly 24 million secrets leaked to public GitHub in 2024 — shows that human review does not catch this class of mistake. Automated detection running on every commit and in CI is the only approach that scales, and it never gets tired or distracted.
What is the difference between pattern matching and entropy analysis?
Pattern matching uses regular expressions for known credential formats, so it precisely identifies things like AWS keys or GitHub tokens by their fixed prefixes but misses generic passwords. Entropy analysis measures how random a string is, catching high-randomness secrets that have no recognizable format. Effective scanners use both and then validate candidates to suppress false positives from example and test values.
Do I need to scan git history or just the latest code?
You must scan history. Git keeps every historical version of a file, so a secret you deleted from the current commit is still fully readable — and scrapeable — in earlier commits. Tools like gitleaks and trufflehog can scan all commits, and any secret found in history must be both purged with a history rewrite and rotated, since deletion alone does not revoke it.
A scan flagged a secret — is deleting it from the code enough?
No. Deleting the code removes the value going forward but leaves it in git history, and the credential itself is still valid at the provider. You must rotate or revoke the secret so it can no longer be used, purge it from history with a rewrite, and confirm the old credential now returns an authentication error before considering the incident closed.