Secrets Detection Pre-Commit
Catch secrets before commit.
Pre-commit hook
Secrets accidentally committed to source control are the most common credential leak path. An engineer commits a config file with a real API key in it; the commit lands on GitHub; bots scanning public repositories find the key within minutes; the credential is compromised before the engineer realizes the mistake. The defense is detection at the commit time, before the bad commit ever leaves the developer's machine.
What pre-commit secret detection looks like:
- gitleaks for full-repo and incremental scanning.: gitleaks is the dominant open-source secret scanner. Run as a pre-commit hook, it scans the staged changes for known secret patterns (API keys, certificates, passwords with high entropy). Detected secrets block the commit; the engineer fixes before pushing.
- detect-secrets for baseline-aware scanning.: Yelp's detect-secrets is similar but designed for incremental adoption. It maintains a baseline of known false positives (real secrets that have been flagged but verified as not actually secrets, like example values). Only new findings outside the baseline block; existing findings are tracked but do not block.
- Fast; runs on every commit.: The hook runs in milliseconds for typical commits. The performance cost is negligible; the engineer does not feel it. This is the property that makes pre-commit hooks viable as the first line of defense.
- Catches the obvious cases.: AWS access keys, GitHub tokens, JWT-shaped secrets, RSA private keys, common API key formats. Each has a distinctive pattern; the hook recognizes them. The vast majority of accidental commits are obvious shapes that get caught.
- Local-only by default.: The hook runs on the engineer's machine before the commit is made. The bad data never reaches the remote. This is much better than the alternative: detect in CI after push, then deal with the fact that the secret is now in the public git history.
Pre-commit hooks are the cheapest and earliest defense. The engineer who would have committed a secret instead gets a friendly "you have a secret in this commit" message and fixes it locally.
CI fallback
Pre-commit hooks rely on the engineer having them installed. Some engineers do not. Some commits come from external sources (other tools, automation, contributors who skipped the hook). The CI-side scan is the fallback that catches what local hooks miss.
- CI scans the diff on every PR.: The CI pipeline includes a step that runs the same secret scanner against the PR's diff. Anything detected fails the PR check; the merge is blocked until the secret is removed and rotated.
- Catches what hooks miss.: Engineers who have not installed the hook, contractors using their own tooling, automated systems pushing commits, all bypass the local hook. The CI scan catches these. The two layers compound; either alone has gaps; both together have very few.
- Repository-level secret scanning too.: GitHub's native secret scanning, GitLab's secret detection, similar features in other platforms scan the entire repository continuously. They detect secrets that landed before the scanner was deployed, secrets in old branches, secrets in commit messages. The repository scan is the third layer.
- Same scanner as the pre-commit hook.: The CI uses the same scanning tool as pre-commit. Identical configuration; identical detection rules. Engineers who pass pre-commit pass CI; engineers who skip pre-commit get caught in CI. The two layers do not produce surprise differences.
- Failure messages are actionable.: The CI failure says exactly which file and line contains the suspected secret. The engineer can fix it without playing detective. The fix is removing the secret AND rotating it (because the secret is now in git history regardless of whether the PR merges).
The two-layer detection (pre-commit local plus CI fallback) closes most of the accidental-commit gap. The remaining cases are where the scanner does not recognize the secret pattern; those are caught by the third layer (repository-level continuous scanning).
Respond
The hardest part of secret detection is what to do when one is detected after it has already been committed. The instinct is to delete the commit and pretend it did not happen. The instinct is wrong; the secret has been compromised the moment it left the encrypted boundary.
- Detected equals rotate immediately.: When a secret is detected in source control, treat it as compromised. Rotate the secret in the upstream system; invalidate the old value; deploy services using the new value. The clock starts when the secret was committed, not when it was detected; assume the worst.
- Don't just amend the commit.: Removing the commit from git history does not unleak the secret. The bad commit was on someone's developer machine, possibly on the CI runner, possibly indexed by GitHub's API even before the deletion. Anyone who pulled before the deletion has a copy. Treat as leaked.
- Treat as if leaked publicly.: Even private repos have audit-log access; even short-lived branches replicate to backups; even immediately-deleted commits get cached. The conservative assumption is that the secret is now in many places. Rotate accordingly.
- Document the incident.: The detection and rotation get logged in the security incident tracker. Pattern emerges across detection events: which kinds of secrets, which engineers, which tools. The pattern informs further training or process changes.
- Postmortem if the secret was sensitive.: A leaked test API key may not warrant a postmortem; a leaked production database password does. The threshold for postmortem matches the severity. The postmortem produces structural changes that prevent recurrence.
Secret detection at commit time is the discipline that prevents the most common credential leak path. Nova AI Ops integrates with pre-commit hooks, CI scanning, and repository-level scanning, surfaces detection events as security incidents with rotation tracking, and produces the audit trail compliance frameworks expect.