A pre-commit hook stops credentials before they enter repository history. It scans staged content and blocks the commit on findings. It also blocks when the scan cannot complete, so an unavailable scanner cannot look clean.
From inside a git repo:
keyhog hook installIf a non-KeyHog pre-commit hook already exists, installation refuses to replace
it. Pass keyhog hook install --force only when replacement is intentional;
keyhog hook uninstall removes only the KeyHog-owned hook.
That writes a .git/hooks/pre-commit script that calls
keyhog scan --fast --git-staged --backend cpu (the same command
.pre-commit-hooks.yaml exposes for the pre-commit framework).
The next git commit invokes the hook.
If keyhog is missing from PATH, the hook blocks the commit because the
security scan did not run. Install KeyHog, fix PATH, or remove
.git/hooks/pre-commit if the repository should not be protected.
This repository's hook uses language: system. Follow the
pinned verified install
for the KeyHog binary, then confirm that it is on PATH:
keyhog --versionAdd the following to .pre-commit-config.yaml:
repos:
- repo: https://github.com/santhreal/keyhog
rev: v0.5.47
hooks:
- id: keyhog
stages: [pre-commit]Run pre-commit install once. The hook then runs on every commit. The rev
pin selects the hook definition. It does not install or pin the keyhog binary.
Keep the binary and hook definition on compatible release versions.
keyhog scan --git-staged walks the index (the set of files git
is about to commit), not the working tree. Why this matters:
- A file you've modified but not
git added is NOT scanned. You're free to keep credentials in scratch files as long as you don't stage them. - A file you've staged then modified gets scanned in the staged
form, not the working-tree form. The scanner sees what
git commitwould commit.
The walk only includes files that are part of this commit. Runtime depends on the staged bytes, detector corpus, binary, and host; use the command's reported duration to characterize a repository.
Stderr:
$ git commit -m "add staging config"
┌ CRITICAL ─── Stripe Secret Key
│ Secret: sk_l...p7dc
│ Location: src/config/staging.env:14
│ Confidence: ■■■■■■ 100%
│ Action: Roll the exposed Stripe secret key in the Dashboard, update production consumers, then delete the old key.
│ Docs: https://docs.stripe.com/keys#roll-api-key
└─────────────────────────────────────────────
━━━ Results ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1 secret found · 1 unverified
1. Revoke active secrets in the provider's dashboard.
The hook runs exec keyhog scan --fast --git-staged --backend cpu, so this is
the ordinary scan report over the staged blobs. Exit 1 means findings and
aborts the commit. Exit 10 would mean a confirmed live credential, although
the shipped hook does not enable verification. Every operational nonzero exit
also aborts the commit because the scan did not complete. Your staged work
remains intact. You can then:
- Remove the credential, stage the fix, and commit again.
- Replace it with a placeholder and load the value from the environment.
- For a false positive, add its hash to
.keyhogignoreor add a narrowly scoped predicate rule to.keyhogignore.toml. Record the reason and owner beside the exception.
git commit --no-verifyThat bypasses the hook. KeyHog logs nothing about it; that's your
prerogative. Use it sparingly. A team norm of --no-verify for
"trust me" commits defeats the point of the hook.
A better pattern when a legitimate-looking credential needs to ship (e.g. a public OAuth client_id that vendor docs say to commit):
- Add its hash to
.keyhogignoreashash:+ the bare 64-character SHA-256 hex digest (nosha256:prefix; that spelling is baseline-file-only):hash:5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8 - Commit the suppression file alongside the credential.
- The next commit sees the hash and skips it.
This way the next contributor doesn't have to learn the trick.
If a pre-commit scan feels slow:
keyhog daemon start(unix only). The daemon holds the compiled scanner in memory for editor-save or hook glue that scans stdin or one regular file. The default staged-file hook uses the in-process orchestrator because git source expansion, baseline policy, and verification are not daemon work.--fastselects the documented reduced-cost scan policy. Keep the full scan in CI so decoded, entropy, and deeper paths remain covered.
keyhog hook uninstallThis removes .git/hooks/pre-commit only when it carries the generated KeyHog
marker. If you edited the hook, keyhog hook uninstall refuses to touch it.
Remove that hook by hand. For the pre-commit framework, delete the KeyHog
stanza from .pre-commit-config.yaml and run pre-commit clean.