Detect secrets
detect-secrets runs on every PreToolUse for git commit and
fails the call if any staged file contains a recognisable
credential pattern. It’s the second line of defence after the
.env.octopus / .gitignore convention — the line that catches
the moment when a fresh credential lands inline in a config or
a script.
Why this exists
Hardcoded secrets are the dominant cause of credentials leaking
to public repositories. The signal-to-noise ratio is high:
real secrets follow narrow grammars (sk_live_… for Stripe,
xoxb-… for Slack, AKIA… for AWS access keys, ghp_… for
GitHub tokens, JWT three-segment base64), so regex detection
catches the vast majority of accidental commits with very few
false positives.
The hook runs before the commit is created, so a blocked secret never enters git history — even local. That matters: once a secret hits a commit object, even amending and force-pushing doesn’t always erase it from forks, mirrors, and caches.
Patterns detected
The current ruleset covers the providers that show up in this
codebase’s .env.example files plus a few high-blast-radius
ones added defensively:
- AWS access key IDs (
AKIA,ASIAprefixes) - Stripe live and test keys (
sk_live_,sk_test_,pk_live_) - SendGrid (
SG.…) - Slack bot and user tokens (
xoxb-,xoxp-,xoxa-) - GitHub personal access tokens (
ghp_,gho_,ghu_,ghs_,ghr_) - OpenAI keys (
sk-proj-…,sk-…) - Generic JWTs (three base64url segments separated by dots)
- Private key blocks (
-----BEGIN … PRIVATE KEY-----)
False positives
The patterns are tight, but the JWT and generic key patterns can match in two legitimate places:
- Example values in docs and READMEs — placeholders that happen
to look like the real shape (
sk-test-xxxxxxxx…). - Inline tests for the secret detector itself.
For docs and tests, the convention is to prefix or suffix with
example, placeholder, XXXX, or use deliberately invalid
characters so the pattern doesn’t match. When a real false
positive does occur, file it as a bug and tighten the regex —
don’t add an inline ignore.
How to bypass
There is no bypass marker by design. If a value looks like a
secret to the hook, it looks like one to a future reader too —
fix the value (move to .env.octopus, rotate, or replace with a
clearly-fake placeholder) rather than annotating around the
warning.
Pairing with the audit-security skill
detect-secrets catches the moment of accidental introduction.
The audit-security skill catches secrets that slipped through
earlier — running a wider scan across the working tree, history,
and .env* files. They’re complementary: one is a fast PreToolUse
gate, the other is a deliberate audit pass before merge.