By Stack
Stop secrets before they commit with gitleaks: catch API-key leaks before the push
Commit an API key by accident and it stays in Git history, leaked for good. How gitleaks stops secrets at two gates — a pre-commit hook and CI — plus the revocation step that detection alone doesn't finish.
For: anyone using Git in solo or small-team development, worried about "what if I commit an API key by accident?" No attacker mechanics here — just the machinery for stopping secrets from leaking out of your own repository.
This site's view: .gitignore alone can't protect secrets
"My .env is in .gitignore, so I'm fine" is a common line — and it has holes. .gitignore only keeps new files from being tracked; it can't catch secrets already committed, ones force-added in a hurry with git add -f, or unexpected names like .env.local.bak. It blocks part of the entrance only. You need something that actually looks at commit contents and flags "secret-looking strings" — a detector. That's what gitleaks is for.
Why stop it "before the commit"
Secrets are dangerous because Git keeps history forever. Delete it from the latest file and it remains in past commits. And the moment it's pushed, that history is copied to other machines, servers, and CI logs.
So secret defense is really about prevention before the leak, not recovery after it. It's the same idea as the "don't leave secrets in a public directory" inventory (→ the webroot inventory), carried into the world of code.
Where the gates go
On the path a secret takes from code to the world, you can place two gates: at the moment of the local commit, and just before it's shared (CI).
secret in code
API key, key, token
gate 1: pre-commit
detect & abort locally at commit
gate 2: CI / cron
detect after push, before merge/deploy
public / shared
past here, treat as leaked
How to wire gitleaks in
Scan existing history first
gitleaks detect. Flushing out secrets sleeping in past commits is the first job. Anything found here is, as below, assumed to need revocation.Build gate 1 with a pre-commit hook
gitleaks protect --staged on every commit to abort on the spot any commit containing a secret. Add it to a pre-commit framework (.pre-commit-config.yaml) so the same check applies for everyone, locally.Build gate 2 in CI / cron
gitleaks detect as a CI job — or, for self-hosted setups, as a periodic scan — to catch what slips through (the same machine-monitoring mindset as dependency audits).Tune false positives in .gitleaks.toml
.gitleaks.toml. The right practice is not "silence it" but "record why it's safe" — an exclusion with no rationale is the seed of the next incident.On detection, 'revoke' comes first; rewriting history comes after
When you find a secret that was committed and pushed, the top priority is revoking and reissuing (rotating) that key or token. Erasing it from history with git filter-repo matters, but it's only cleanup to "stop it spreading further." Assume a secret that reached a public repo, a fork, a CI log, or someone else's clone is unrecoverable — invalidate it first, then clean history. Reverse the order and it gets used while you're still deleting.
Relying on .gitignore
- only prevents new tracking
- secrets already committed sail straight through
- powerless against
git add -for odd file names - can't verify "I didn't mean to add that"
gitleaks (detection + revocation practice)
- actually inspects the working tree and history contents
- stops it at two gates: pre-commit and CI
- on detection, a procedure that runs through to revocation
- false positives excluded with a recorded rationale
What this site does itself
This site is built on a foundation of keeping secrets out of Git entirely — connection strings and API keys live only in protected config on the server (a permission-restricted env file), never in plaintext in the repo or in handoff notes (→ keeping secrets out of git / self-hosted Git vs GitHub). On top of that, we layer detectors on the assumption that humans will always slip. The design guarantees "don't put it in," and a scan like gitleaks catches "it got in anyway" — those two layers are this site's defense against secret leaks. The principle of handling secrets itself is continuous with .env files and secrets and storing passwords safely.
Read next
FAQ
QWhat is gitleaks?
A free tool that scans a Git repository's working tree and commit history to detect whether secrets — API keys, private keys, tokens — have been committed. It finds 'secret-looking strings' with regex rules and string entropy (randomness), and can run as a pre-commit hook or in CI for automatic checks.
QDoesn't putting it in .gitignore protect secrets?
Not enough. .gitignore only stops 'new tracking' — it can't detect secrets that are already committed, or ones force-added with git add -f. It blocks only part of the accident, so pair it with a detector like gitleaks in both pre-commit and CI.
QWhat if I accidentally committed and pushed a secret?
Treat that secret as leaked. The top priority is not rewriting history but revoking and rotating (reissuing) the exposed key or token. Assume a secret that hit a public repo or a log can't be recalled — invalidate it first, then clean up history and add prevention (gitleaks).