Last month I ran trufflehog against one of my private repos — a homelab automation project I’d never planned to open-source. It found 14 live secrets. AWS keys, a Telegram bot token, two database passwords, and a Stripe test key that still had access to customer data. All committed between 2022 and 2024, scattered across dozens of commits.
The fix took me about 20 minutes. I now run two tools as pre-commit hooks that catch secrets before they ever reach .git/objects. Here’s exactly how I set it up, what each tool catches that the other misses, and the one configuration mistake that will give you false confidence.
Why Two Tools: git-secrets vs trufflehog
I use both git-secrets and trufflehog because they work differently and catch different things.
git-secrets is pattern-based. It ships with AWS-specific patterns out of the box (matches AKIA[0-9A-Z]{16} and similar) and lets you add custom regexes. It’s fast — sub-100ms on most commits — and runs as a native git hook. The downside: it only knows what you tell it to look for.
trufflehog uses entropy detection and pattern matching. It calculates Shannon entropy on strings and flags anything that looks random enough to be a key. Version 3 also verifies secrets against live APIs — it’ll actually try your AWS key against STS to confirm it’s active. This is slower (2-5 seconds per commit) but catches novel secret formats that pattern matching misses.
In my 14-secret audit, git-secrets would have caught 9 of them. trufflehog caught all 14. But git-secrets has zero false positives in my workflow, while trufflehog flags about 1 false positive per week on base64-encoded config blobs.
Setting Up git-secrets as a Pre-Commit Hook
Install it:
brew install git-secrets # macOS
# or
git clone https://github.com/awslabs/git-secrets.git
cd git-secrets && make install
Register it in your repo:
cd your-repo
git secrets --install
git secrets --register-aws
That --register-aws flag adds patterns for AWS access keys, secret keys, and account IDs. Now add your own patterns for whatever services you use:
# Telegram bot tokens (numeric:alphanumeric format)
git secrets --add '[0-9]{8,10}:[A-Za-z0-9_-]{35}'
# Stripe keys
git secrets --add 'sk_(live|test)_[A-Za-z0-9]{24,}'
# Generic high-entropy passwords in connection strings
git secrets --add 'password\s*=\s*[^\s]{12,}'
Test it works:
echo "AKIAIOSFODNN7EXAMPLE" > test.txt
git add test.txt
git commit -m "test"
# Output: [ERROR] Matched one or more prohibited patterns
One gotcha: git secrets --install only sets up hooks in that repo. For global coverage across all repos:
git secrets --install ~/.git-templates/git-secrets
git config --global init.templateDir ~/.git-templates/git-secrets
Adding trufflehog as a Pre-Commit Hook
I use the pre-commit framework for trufflehog since it handles updates and version pinning:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/trufflesecurity/trufflehog
rev: v3.78.1
hooks:
- id: trufflehog
entry: trufflehog git file://. --since-commit HEAD --only-verified --fail
stages: [commit, push]
The --only-verified flag is important. Without it, trufflehog reports every high-entropy string — UUIDs, hashes, random test data. With it, you only get alerts for secrets that are confirmed active against their respective APIs. This drops false positives from ~30/week to about 1.
Install and activate:
pip install pre-commit
pre-commit install
pre-commit install --hook-type pre-push
The Configuration Mistake That Gives False Confidence
Here’s what tripped me up for months: git-secrets only scans staged changes by default, not the full file. If you have a secret on line 5 and you modify line 50, git-secrets won’t flag it because line 5 isn’t in the diff.
This matters because secrets often enter a file in one commit and stay there forever. The pre-commit hook only fires on new changes, so existing secrets remain invisible.
Fix: run a full-repo scan on a schedule. I have this in a weekly cron:
# Scan entire repo history
trufflehog git file:///path/to/repo --only-verified --json > /tmp/secrets-audit.json
# Scan all current files (not just diffs)
git secrets --scan
I pipe the output to ntfy for notifications. If something shows up, I rotate the credential immediately and use git filter-repo to purge it from history:
git filter-repo --invert-paths --path secrets.env
# Then force-push and tell collaborators to re-clone
What About GitHub’s Built-in Secret Scanning?
GitHub’s secret scanning (free for public repos, paid for private) is solid but it’s a safety net, not prevention. By the time GitHub alerts you, the secret has already been pushed to a remote. If your repo was public for even 5 seconds, bots have already scraped it — I’ve seen AWS keys exploited within 4 minutes of being pushed.
Pre-commit hooks stop the secret locally. That’s the difference between “we caught it early” and “we need to rotate everything and audit CloudTrail logs.”
My Full .pre-commit-config.yaml
Here’s what I run on every project now:
repos:
- repo: https://github.com/trufflesecurity/trufflehog
rev: v3.78.1
hooks:
- id: trufflehog
entry: trufflehog git file://. --since-commit HEAD --only-verified --fail
stages: [commit, push]
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.4
hooks:
- id: gitleaks
stages: [commit]
I actually dropped git-secrets from the pre-commit config because gitleaks covers similar patterns with better regex coverage and active maintenance. I still keep git-secrets installed globally as a backup layer — defense in depth.
Total overhead per commit: about 3 seconds. That’s a tiny price for never accidentally leaking credentials again.
Hardware Keys Add Another Layer
If you’re serious about credential security, pairing this with a hardware security key like the YubiKey 5 NFC means even if a secret leaks, an attacker can’t use it without physical access to your key. I wrote about my YubiKey migration previously — the short version is it took a weekend and now my GitHub, AWS, and Stripe accounts all require physical touch to authenticate.
For teams, the YubiKey 5C NFC (USB-C) is the better pick since most developer laptops have dropped USB-A at this point.
Practical Next Steps
If you do nothing else today: run trufflehog git file://. in your most-used repo. You might be surprised. I was.
Then set up the pre-commit hooks. It takes 5 minutes and the muscle-memory of “commit blocked — fix it — re-commit” builds fast. After a month you’ll instinctively reach for environment variables instead of hardcoding strings.
Related: I previously ran Trivy against my homelab containers and found similar hygiene issues. Security scanning is one of those things where the first run is always humbling.
Full disclosure: links to YubiKey products above are affiliate links.
📡 Get free daily market intelligence and trading signals: Join Alpha Signal on Telegram — AI-driven analysis delivered before market open.
📧 Get weekly insights on security, trading, and tech. No spam, unsubscribe anytime.
Leave a Reply