Pre-Commit Hooks for Secret Detection
Category: Security / Development Tools
Status: Production Ready
Last Updated: 2026-05-27
Overview
Pre-commit hooks are scripts that run automatically before each git commit. They validate your changes and block commits if they detect problems like:
- API keys, tokens, passwords
- AWS/Cloud credentials
- Private SSH/GPG keys
- Internal hostnames, IP addresses
- Sensitive configuration data
The goal: Catch secrets before they enter git history, preventing leaks entirely.
Why Pre-Commit Hooks?
The Problem Without Hooks
Typical leak scenario:
# Day 1: You accidentally commit a secret
echo "API_KEY=abc123xyz789" > config.env
git add config.env
git commit -m "Add config"
git push origin main
# Day 2: You realize the mistake
❌ Secret is now in git history FOREVER
❌ Accessible to anyone with repo access
❌ Potentially exposed on GitHub/GitLab
❌ Requires complex git history rewrite to fix
The Solution With Pre-Commit Hooks
Protected workflow:
# You try to commit a secret
echo "API_KEY=abc123xyz789" > config.env
git add config.env
git commit -m "Add config"
# Pre-commit hook runs automatically:
🛡️ Scanning config.env for secrets...
❌ SECRET DETECTED!
File: config.env
Line 1: API_KEY=abc123xyz789
Pattern: High entropy string (possible API key)
COMMIT BLOCKED. Remove the secret and try again.
# Your commit is REJECTED - secret never enters git history
Result: - ✅ Leak prevented automatically - ✅ No git history contamination - ✅ No complex cleanup needed - ✅ You're forced to fix it immediately
How Pre-Commit Hooks Work
Git Hook Lifecycle
┌─────────────────────────────────────────────────┐
│ 1. You: git add file.txt │
│ 2. You: git commit -m "message" │
│ 3. Git: Running .git/hooks/pre-commit... │
│ ├─> Hook scans staged files │
│ ├─> If OK: ✅ Commit proceeds │
│ └─> If FAIL: ❌ Commit blocked │
│ 4. Result: Commit created OR rejected │
└─────────────────────────────────────────────────┘
Where Hooks Live
Git hooks directory:
your-repo/
└── .git/
└── hooks/
├── pre-commit # Runs before commit
├── pre-push # Runs before push
├── commit-msg # Validates commit message
└── ...
Pre-commit hook is just a script:
#!/bin/bash
# .git/hooks/pre-commit
echo "Scanning for secrets..."
detect-secrets scan --baseline .secrets.baseline
if [ $? -ne 0 ]; then
echo "❌ Secrets detected! Commit blocked."
exit 1 # Non-zero exit = block commit
fi
exit 0 # Zero exit = allow commit
Available Tools
1. rh-pre-commit (Red Hat Internal)
Source: Red Hat internal tool
Best for: Red Hat employees working with Red Hat systems
License: Proprietary (Red Hat internal)
Installation
# Install from Red Hat internal PyPI
pip3 install --user rh-pre-commit
# Activate in a repository
cd ~/projects/your-repo
rh-pre-commit install
# Verify
ls -la .git/hooks/pre-commit
What It Detects
- ✅ Red Hat specific API keys
- ✅ BREW credentials
- ✅ Datadog API keys
- ✅ AWS credentials
- ✅ GitHub/GitLab tokens
- ✅ Private SSH/GPG keys
- ✅ Internal Red Hat hostnames
- ✅ High entropy strings (generic secrets)
Configuration
Default behavior: Scans all staged files
Custom configuration (optional):
# ~/.config/rh-pre-commit/config.yaml
exclude_patterns:
- "*.md" # Skip markdown files
- "test/*" # Skip test directory
sensitivity: high # high, medium, low
Bypassing (Emergency Only)
⚠️ WARNING: Only use --no-verify if you're 100% sure no secrets are present.
2. detect-secrets (Yelp - Open Source)
Source: https://github.com/Yelp/detect-secrets
Best for: General purpose secret detection
License: Apache 2.0 (Open Source)
Installation
# Install
pip3 install --user detect-secrets
# Initialize in repository
cd ~/projects/your-repo
detect-secrets scan > .secrets.baseline
# Add baseline to git
git add .secrets.baseline
git commit -m "Add secrets baseline"
Setup Pre-Commit Hook
Method 1: Using pre-commit framework
# Install pre-commit framework
pip3 install --user pre-commit
# Create .pre-commit-config.yaml
cat > .pre-commit-config.yaml << 'EOF'
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
EOF
# Install hooks
pre-commit install
Method 2: Manual hook script
# Create pre-commit hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
detect-secrets scan --baseline .secrets.baseline
if [ $? -ne 0 ]; then
echo "❌ Secrets detected! Run: detect-secrets scan --update .secrets.baseline"
exit 1
fi
EOF
chmod +x .git/hooks/pre-commit
Auditing Detected Secrets
# Review potential secrets
detect-secrets audit .secrets.baseline
# Interactive audit interface:
# - Mark as real secret (will block commits)
# - Mark as false positive (will ignore)
What It Detects
- ✅ AWS keys
- ✅ Azure keys
- ✅ GCP keys
- ✅ Slack tokens
- ✅ Stripe keys
- ✅ Private keys (PEM, SSH)
- ✅ High entropy strings
- ✅ Base64 encoded strings
Custom Plugins
# my_custom_detector.py
from detect_secrets.plugins.base import RegexBasedDetector
class MyAPIKeyDetector(RegexBasedDetector):
secret_type = 'My API Key'
denylist = [
re.compile(r'my_api_key_[a-zA-Z0-9]{32}'),
]
3. git-secrets (AWS - Open Source)
Source: https://github.com/awslabs/git-secrets
Best for: AWS-focused projects
License: Apache 2.0 (Open Source)
Installation
# macOS
brew install git-secrets
# Linux (manual)
git clone https://github.com/awslabs/git-secrets.git
cd git-secrets
sudo make install
Setup
cd ~/projects/your-repo
# Install hooks
git secrets --install
# Register AWS patterns
git secrets --register-aws
# Add custom patterns
git secrets --add 'api_key.*=.*[A-Za-z0-9]{32}'
What It Detects
- ✅ AWS Access Key ID
- ✅ AWS Secret Access Key
- ✅ AWS Session Token
- ✅ Custom regex patterns
Scanning Existing History
# Scan entire git history
git secrets --scan-history
# Scan specific branch
git secrets --scan-history origin/main
4. gitleaks (Open Source)
Source: https://github.com/gitleaks/gitleaks
Best for: Comprehensive scanning, CI/CD integration
License: MIT (Open Source)
Installation
# macOS
brew install gitleaks
# Linux
wget https://github.com/gitleaks/gitleaks/releases/download/v8.18.0/gitleaks_8.18.0_linux_x64.tar.gz
tar -xzf gitleaks_8.18.0_linux_x64.tar.gz
sudo mv gitleaks /usr/local/bin/
Pre-Commit Integration
# Using pre-commit framework
cat > .pre-commit-config.yaml << 'EOF'
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
EOF
pre-commit install
Standalone Usage
# Scan current changes
gitleaks detect --source . --verbose
# Scan git history
gitleaks detect --source . --log-opts="--all"
# Generate report
gitleaks detect --source . --report-format json --report-path report.json
Custom Rules
# .gitleaks.toml
title = "Custom gitleaks config"
[[rules]]
id = "my-api-key"
description = "My Company API Key"
regex = '''mycompany_api_key_[a-zA-Z0-9]{40}'''
[[rules]]
id = "internal-hostname"
description = "Internal hostname"
regex = '''\.internal\.mycompany\.com'''
Comparison Matrix
| Feature | rh-pre-commit | detect-secrets | git-secrets | gitleaks |
|---|---|---|---|---|
| License | Proprietary (RH) | Apache 2.0 | Apache 2.0 | MIT |
| Maintenance | Red Hat | Yelp | AWS | Gitleaks org |
| Install | pip install |
pip install |
Manual/brew | Binary/brew |
| Speed | Fast | Fast | Fast | Very Fast (Go) |
| Accuracy | High (RH tuned) | High | Medium | Very High |
| False Positives | Low | Medium | High | Low |
| Custom Rules | Limited | Yes (Python) | Yes (regex) | Yes (TOML) |
| Baseline | No | Yes | No | Yes |
| History Scan | No | No | Yes | Yes |
| CI/CD | No | Yes | Yes | Yes |
| AWS Focus | No | No | Yes | No |
| Red Hat Focus | Yes | No | No | No |
Recommended Setup by Use Case
Use Case 1: Red Hat Employee, Red Hat Projects
Recommended: rh-pre-commit
Why: - Optimized for Red Hat secrets - Knows Red Hat internal patterns - Lower false positive rate for RH work - Officially supported
Use Case 2: Personal Projects (No Red Hat Work)
Recommended: detect-secrets + pre-commit framework
pip3 install --user pre-commit detect-secrets
cd ~/projects/personal-project
# Initialize
detect-secrets scan > .secrets.baseline
# Setup pre-commit
cat > .pre-commit-config.yaml << 'EOF'
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
EOF
pre-commit install
git add .secrets.baseline .pre-commit-config.yaml
git commit -m "Add secret detection"
Why: - Open source - Flexible baseline system - Good accuracy - Widely used
Use Case 3: AWS-Heavy Projects
Recommended: git-secrets
brew install git-secrets # or manual install
cd ~/projects/aws-project
git secrets --install
git secrets --register-aws
Why: - AWS-specific patterns - Built by AWS team - Comprehensive AWS coverage
Use Case 4: CI/CD Pipeline Integration
Recommended: gitleaks
# In CI/CD pipeline
docker run --rm -v $(pwd):/repo zricethezav/gitleaks:latest \
detect --source /repo --verbose --report-format json
Why: - Fast (written in Go) - Standalone binary - JSON output for automation - Excellent CI/CD integration
Use Case 5: Mixed (Red Hat + Personal)
Recommended: Both rh-pre-commit AND detect-secrets
# Red Hat repos
cd ~/work/red-hat-project
rh-pre-commit install
# Personal repos
cd ~/projects/personal-project
detect-secrets scan > .secrets.baseline
pre-commit install # with detect-secrets config
Why: - Best of both worlds - Use right tool for each project - No conflicts between tools
Best Practices
1. Never Bypass Unless Absolutely Necessary
# ❌ BAD - Routine bypass
git commit --no-verify -m "Quick fix"
# ✅ GOOD - Only in emergencies
# Emergency production fix, secret verified absent
git commit --no-verify -m "Hotfix: Fix critical bug"
2. Audit Baselines Regularly
# Review baseline quarterly
detect-secrets audit .secrets.baseline
# Remove outdated entries
# Mark new false positives
3. Combine Multiple Layers
Defense in depth:
Layer 1: Pre-commit hook (local)
Layer 2: CI/CD scan (server)
Layer 3: GitHub Secret Scanning (remote)
Layer 4: Periodic repo audits
4. Document Exceptions
# .secrets.baseline or README.md
# Known false positives:
# - test/fixtures/sample_api_key.txt (test data, not real)
# - docs/examples/config.yaml (placeholder values)
5. Use Environment Variables
Never commit secrets, even in examples:
6. Template Files, Not Real Configs
# Commit: config.yaml.example
api_key: YOUR_API_KEY_HERE
database_password: YOUR_PASSWORD_HERE
# .gitignore: config.yaml (actual file)
Setup instructions:
7. Enable Hook in All Repos
Global template for new repos:
# Create global git template
mkdir -p ~/.git-template/hooks
# Add pre-commit hook
cat > ~/.git-template/hooks/pre-commit << 'EOF'
#!/bin/bash
if command -v detect-secrets &> /dev/null; then
detect-secrets scan --baseline .secrets.baseline 2>/dev/null
fi
EOF
chmod +x ~/.git-template/hooks/pre-commit
# Configure git to use template
git config --global init.templateDir '~/.git-template'
Now all new repos get pre-commit hook automatically!
Troubleshooting
Issue: Hook Not Running
Symptom: Commit succeeds even with secrets
Check:
# 1. Verify hook exists
ls -la .git/hooks/pre-commit
# 2. Check if executable
file .git/hooks/pre-commit
# 3. Test manually
.git/hooks/pre-commit
Fix:
# Make executable
chmod +x .git/hooks/pre-commit
# Reinstall
rh-pre-commit install
# or
pre-commit install
Issue: Too Many False Positives
Symptom: Hook blocks legitimate commits
Solution 1: Update baseline (detect-secrets)
detect-secrets scan --update .secrets.baseline
detect-secrets audit .secrets.baseline
# Mark false positives as "No"
Solution 2: Add exclusions
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
exclude: 'test/.*|docs/examples/.*'
Issue: Hook Slows Down Commits
Symptom: git commit takes 10+ seconds
Solution: Limit scan scope
Or use faster tool:
Issue: Need Emergency Bypass
Scenario: Production down, need immediate fix, hook blocking
Safe bypass:
# 1. Verify NO secrets in your changes
git diff --staged
# 2. Bypass hook
git commit --no-verify -m "Emergency: Fix production outage"
# 3. IMMEDIATELY after: Scan manually
detect-secrets scan
Document why:
# In commit message or follow-up
git commit --amend -m "Emergency: Fix production outage
Hook bypassed due to P1 incident.
Manual scan conducted post-commit - no secrets present.
Incident: INC-12345"
Integration Examples
GitHub Actions
# .github/workflows/secret-scan.yml
name: Secret Scan
on: [push, pull_request]
jobs:
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Run Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GitLab CI
# .gitlab-ci.yml
secret_scan:
stage: test
image: zricethezav/gitleaks:latest
script:
- gitleaks detect --source . --verbose --report-format json
artifacts:
reports:
gitleaks: gitleaks-report.json
only:
- merge_requests
- main
Pre-Commit Framework (Multi-Tool)
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-added-large-files
- id: check-yaml
- id: end-of-file-fixer
Testing Your Setup
Test 1: Detect API Key
# Create test file with fake API key
echo "api_key: test_abc123def456ghi789jkl012" > test-secret.txt
# Stage file
git add test-secret.txt
# Try to commit (should FAIL)
git commit -m "Test secret detection"
# Expected: ❌ Commit blocked
# Clean up
git reset HEAD test-secret.txt
rm test-secret.txt
Test 2: Detect AWS Credentials
# Create test AWS config
cat > test-aws.txt << 'EOF'
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
EOF
# Try to commit (should FAIL)
git add test-aws.txt
git commit -m "Test AWS detection"
# Clean up
git reset HEAD test-aws.txt
rm test-aws.txt
Test 3: Verify Bypass Works
# Create secret
echo "secret: abc123" > bypass-test.txt
git add bypass-test.txt
# Bypass hook
git commit --no-verify -m "Test bypass"
# Expected: ✅ Commit succeeds
# Clean up
git reset --hard HEAD~1
rm bypass-test.txt
Real-World Incident: Case Study
Context: Datadog API key leaked to GitHub
Timeline: 1. Developer documented Datadog Agent config 2. Accidentally included real API key instead of placeholder 3. Committed and pushed to GitHub 4. InfoSec detected leak via Datadog notification 5. API key revoked 6. Git history cleaned (8 hours of work)
Cost: - 8 hours remediation time - InfoSec investigation overhead - Potential security exposure - Team trust impact
Prevention if pre-commit hook was active:
# Developer tries to commit
git add Datadog-Agent-Configuration.md
git commit -m "Add Datadog config"
# Pre-commit hook runs
🛡️ Scanning for secrets...
❌ SECRET DETECTED!
File: Datadog-Agent-Configuration.md
Line 159: api_key: ad1c08df3ba84bb8a68f2ff06a85a4dd
Pattern: Datadog API key
COMMIT BLOCKED.
Replace with placeholder: api_key: ${DATADOG_API_KEY}
# Developer fixes immediately
# TOTAL TIME: 30 seconds
# NO LEAK, NO CLEANUP, NO INCIDENT
Lesson: Pre-commit hooks prevent 99% of secret leaks before they happen.
Maintenance Checklist
Weekly
- Review any bypassed commits (
git log --grep="no-verify")
Monthly
- Update tool versions
Quarterly
- Audit baseline for false positives
- Review and update custom patterns
- Scan git history for historical leaks
Annually
- Full repository secret audit
- Review and update security policies
- Team training on secret management
Resources
Official Documentation: - rh-pre-commit: https://source.redhat.com (internal) - detect-secrets: https://github.com/Yelp/detect-secrets - git-secrets: https://github.com/awslabs/git-secrets - gitleaks: https://github.com/gitleaks/gitleaks - pre-commit framework: https://pre-commit.com
Related Guides: - Git Secret Leak Remediation Guide - GitHub Secret Scanning: https://docs.github.com/en/code-security/secret-scanning - OWASP Secret Management: https://owasp.org/www-community/vulnerabilities/Use_of_hard-coded_password
Summary
Pre-commit hooks are your first line of defense against secret leaks.
Key Takeaways:
1. ✅ Install a pre-commit hook in EVERY repository
2. ✅ Use rh-pre-commit for Red Hat work, detect-secrets for personal projects
3. ✅ Never bypass unless absolutely necessary (--no-verify)
4. ✅ Combine with CI/CD scanning for defense in depth
5. ✅ Use environment variables and templates, not hardcoded secrets
6. ✅ Test your setup regularly
7. ✅ Update tools quarterly
Bottom line: 5 minutes of setup prevents hours of incident response.
Last Updated: 2026-05-27
Next Review: 2026-08-27 (quarterly)
Status: Production Ready - Battle-tested in real incident