Skip to content
>_ITDITDWeb Security Platform

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.

Published 2026-06-12 Updated 2026-06-12 6 min read

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.

stays in history
gone from latest, still in past commits
push = spread
copied to other machines, servers, CI logs
must revoke
a once-leaked key can only be reissued
two gates
stop it at pre-commit and CI

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

The leak path and two gates. Pre-commit stops it locally; CI stops it before merge/deploy.

How to wire gitleaks in

1

Scan existing history first

On adoption, scan the whole repo history once with gitleaks detect. Flushing out secrets sleeping in past commits is the first job. Anything found here is, as below, assumed to need revocation.
2

Build gate 1 with a pre-commit hook

Run 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.
3

Build gate 2 in CI / cron

Hooks can be disabled by each person, so check again before anything is shared. Run 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).
4

Tune false positives in .gitleaks.toml

When dummy test keys or sample values trip it, adjust rules and the allowlist in .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 -f or 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.

FAQ

QWhat is gitleaks?
A

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?
A

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?
A

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).