BlogSecrets

Catch secrets before commit with gitleaks and pre-commit

Block credentials at the git hook, scan history for what already leaked, and wire the same check into CI.

Feb 25, 2025·4 min readBeginner·By the SecOpsLog team · command-tested

Researchers who plant canary AWS keys in a public GitHub commit see unauthorized API calls in under ten minutes. Your private repo is not magically slower — it is just less watched. The cheapest leak to fix is the one that never enters history. gitleaks scans for key patterns (AWS AKIA…, GitHub ghp_…, Slack tokens, private keys) and exits non-zero when it finds a hit. Wire it into pre-commit and the commit aborts before the secret is immortalized.

This walkthrough installs pre-commit, adds the official gitleaks hook, shows what a blocked commit looks like, scans full history for what already leaked, and duplicates the check in CI so --no-verify bypasses do not win. For the broader secrets lifecycle — rotation, honeytokens, org-wide sweeps — continue in Advanced secrets.

Three layers with one scanner binary

Pre-commit catches staged changes. CI catches bypassed hooks and forked PRs. Scheduled org scans catch repos that predates your controls.

1Developer editsconfig with a key2git commitpre-commit runs3gitleaks protectscans staged diff4Block or passcommit aborted on hit5CI gitleaks detectfull tree scan6History scangitleaks detect --log-opts7Rotate + ticketassume compromise

Install pre-commit and add the gitleaks hook

Pin the gitleaks hook to a release tag — @main on a security gate is how you get surprised on a Friday. Run pre-commit install once per clone; hooks live in .git/hooks/pre-commit and call the versions pinned in .pre-commit-config.yaml.

.pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.4
hooks:
- id: gitleaks
args: ['protect', '--staged', '--redact', '--verbose']
bash — enable hooks and trigger a blocklive
pip install pre-commit # or brew install pre-commit
pre-commit install
git commit -m "add prod config"
gitleaks.............................................Failed
Finding: AWS Access Key File: config/prod.env:4
commit aborted — key never enters history

Scan what already happened — and act on it

Pre-commit only protects forward motion. Run gitleaks detect against the full repository to find keys committed before the hook existed — including deleted files still reachable via git log. Use --redact in shared logs and --report-path in CI so security can triage without pasting live credentials into Slack.

bash — audit history and a specific branchlive
gitleaks detect --source . --redact --exit-code 1
3 leaks found across 1,204 commits
gitleaks detect --source . --log-opts="main..feature" --redact
scan only commits on a feature branch vs main
git log -p --all -S "AKIA" -- "*.env" | head -40
manual spot-check for context around a hit
A leaked secret is a rotated secret
Rewriting git history does not revoke a key that was already cloned, forked, or indexed. Assume compromise, rotate in the upstream system (AWS IAM, GitHub, Vault), and open a ticket for every finding older than a week. History rewrite is for shrinking noise, not for undoing exposure.

Backstop in CI — hooks are not enforcement

Anyone can run git commit --no-verify. Protected branches should require CI secret scanning to pass before merge, and org policy should block force-push to default branches without review. The same gitleaks version and config in pre-commit and CI keeps false-positive rates stable.

Add a .gitleaks.toml when defaults false-positive on test fixtures — allowlist paths like testdata/ with a comment explaining why, never a blanket allowlist.regexes = ['.*']. Review allowlists in pull requests the same way you review firewall rules: every exception should have an owner and a expiry.

.gitlab-ci.yml
secret_scan:
stage: test
image: zricethezav/gitleaks:v8.18.4
script:
- gitleaks detect --source . --no-git --redact --exit-code 1 --report-path gl.json
artifacts:
when: on_failure
paths: [gl.json]
Pre-commit vs CI vs org sweep
Pre-commit
Fast feedback at keyboard
Bypassable with --no-verify
Scans staged changes only
CI + scheduled
Required on protected branches
Catches bypassed hooks
Org cron finds legacy repos

Where this goes next

Scanning is detection, not storage policy. Pair gitleaks with SOPS + age so secrets that belong in Git arrive encrypted, push protection on your Git host where available, and honeytokens that alert when touched. The Secrets management foundations course covers where secrets should live — and why Git is never that place in plaintext.

Go deeper in a courseAdvanced secretsScanning at scale, rotation, honeytokens, and Kubernetes delivery patterns.View course

Related posts