Secret Scanning with Gitleaks
Commit API keys to a git repo, then "remove" them. Gitleaks finds them anyway — they're still in history. Install a pre-commit hook that blocks secrets before they ever enter the repository, and verify it catches the next attempt.
Git History is Forever
If a secret was committed — even once, even if later "removed" — it is in git history permanently. Anyone who clones the repo can find it.
Create a Repository with Committed Secrets
mkdir -p ~/demo-repo && cd ~/demo-repo
git init
git config user.email "demo@dangote.com"
git config user.name "Demo User"
# Commit 1: config with credentials
cat > config.py << 'EOF'
DATABASE_PASSWORD = "p@ssw0rd!SuperSecret2024"
DATABASE_USER = "admin"
DATABASE_HOST = "postgres.internal.example.com"
EOF
git add config.py
git commit -m "Add database configuration"
# Commit 2: API keys
cat > .env << 'EOF'
STRIPE_SECRET_KEY=sk_test_zQPyAkXOPdh2IEbhCDN0gZhMbJ83XYZABC12345
AWS_SECRET_ACCESS_KEY=P9Tq/ABcDefGHiJkL+MnOpQrStUvWxYzABcDeF12
GITHUB_TOKEN=ghp_ABcDefGHiJkLmNoPqRsTuVwXyZABcDeFgHiJ12
EOF
git add .env
git commit -m "Add API credentials config"
# Commit 3: "Remove" them — but they're still in history!
cat > .env << 'EOF'
STRIPE_SECRET_KEY=
AWS_SECRET_ACCESS_KEY=
GITHUB_TOKEN=
EOF
git add .env
git commit -m "Move secrets to environment variables"
Scan the Full Git History
gitleaks detect --source ~/demo-repo --verbose 2>&1
Expected: 4+ secrets found, including ones in the "cleaned up" commit.
Gitleaks finds secrets across all commits — including the one where we "removed" them.
Install a Pre-commit Hook
Prevention is better than detection. Stop secrets before they enter history.
cd ~/demo-repo
mkdir -p .git/hooks
cat > .git/hooks/pre-commit << 'HOOK'
#!/bin/sh
echo "Running Gitleaks secret scan..."
gitleaks protect --staged --verbose
if [ $? -ne 0 ]; then
echo ""
echo "COMMIT BLOCKED: Gitleaks detected secrets in staged changes."
exit 1
fi
echo "No secrets detected. Commit allowed."
HOOK
chmod +x .git/hooks/pre-commit
echo "Pre-commit hook installed."
Test the Hook
cd ~/demo-repo
cat > new-secret.py << 'EOF'
STRIPE_SECRET_KEY = "sk_test_zQPyAkXOPdh2IEbhCDN0gZhMbJ83XYZABC12345"
EOF
git add new-secret.py
git commit -m "Add payment integration"
Expected:
Running Gitleaks secret scan...
COMMIT BLOCKED: Gitleaks detected secrets in staged changes.
The commit is blocked. Clean up:
git restore --staged new-secret.py
rm new-secret.py
Key Rule
When a secret is found in history:
- Revoke it immediately — assume it's already compromised
- Rotate it — generate a new credential
- Then clean history (
git filter-repo) — optional, cosmetic only
The order matters: clean history first and you've just hidden the evidence while the attacker still holds the key.
- Previous lesson
- Supply-Chain Security — Image Signing & Verification
- Next lesson
- Runtime Threat Detection with Falco