How to Detect Secrets in GitHub Repositories
Secrets committed to GitHub repositories are the number one cause of credential leaks. Whether it is an AWS key, a database password, or an API token, once a secret enters git history, it persists even after deletion. This guide covers every tool and technique for finding and preventing secret leaks in your repositories.
The Scale of the Problem
GitGuardian's 2025 State of Secrets Sprawl report found 12.8 million new secrets in public GitHub commits in a single year. That is a 28% increase from the previous year. And this only counts public repositories. Private repositories contain even more secrets because developers feel a false sense of security when code is not publicly visible.
The consequences are severe. Research shows that exposed secrets are discovered by automated bots within one to five minutes. AWS keys leaked on GitHub are exploited for cryptocurrency mining within minutes, with bills reaching tens of thousands of dollars. Stripe keys are used to issue fraudulent charges. Database credentials lead to full data exfiltration.
GitHub Native Secret Scanning
GitHub offers built-in secret scanning that detects over 200 secret patterns from 100+ service providers. It is free for public repositories and available with GitHub Advanced Security for private repositories.
Enabling Secret Scanning
- Go to your repository Settings
- Navigate to "Code security and analysis"
- Enable "Secret scanning"
- Enable "Push protection" to block commits containing secrets
Push protection is the most valuable feature because it prevents secrets from ever reaching the repository. When a developer tries to push a commit containing a detected secret, the push is blocked with a clear message explaining what was found and how to fix it.
Limitations of GitHub Secret Scanning
- Only detects known patterns from partnered providers
- Does not detect custom secrets, internal tokens, or generic passwords
- Push protection requires GitHub Advanced Security for private repos ($49/user/month)
- Does not scan existing git history retroactively (only new pushes)
TruffleHog: Deep Git History Scanning
TruffleHog is the most comprehensive open-source secret scanner. It scans the entire git history, including deleted commits, and supports both pattern matching and high-entropy string detection.
# Install TruffleHog
brew install trufflehog
# Scan a GitHub repository (including all history)
trufflehog github --repo=https://github.com/your-org/your-repo
# Scan a local git repository
trufflehog filesystem --directory=/path/to/repo
# Scan an entire GitHub organization
trufflehog github --org=your-org-name
# Scan only verified secrets (reduces false positives)
trufflehog github --repo=https://github.com/your-org/your-repo --only-verified
TruffleHog supports over 800 secret detectors and can verify whether detected secrets are still active by making safe API calls to the relevant service. This dramatically reduces false positives.
Gitleaks: Fast CI/CD Integration
Gitleaks is lightweight, fast, and designed specifically for CI/CD pipeline integration. It uses regex-based rules defined in a TOML configuration file.
# Install Gitleaks
brew install gitleaks
# Scan the entire repository
gitleaks detect --source=/path/to/repo --verbose
# Scan only new commits (ideal for CI/CD)
gitleaks detect --source=. --log-opts="HEAD~1..HEAD"
# Generate a JSON report
gitleaks detect --source=. --report-format=json --report-path=gitleaks-report.json
GitHub Actions Integration
name: Secret Scanning
on: [push, pull_request]
jobs:
gitleaks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Check Your Web Infrastructure Too
Secrets leak through more than just git repos. Exposed .env files, config files, and debug endpoints on your web server are equally dangerous.
Scan Your Domain FreePre-commit Hooks: Stop Secrets Before They Enter Git
The best secret is one that never reaches the repository. Pre-commit hooks run locally before each commit and block commits containing detected secrets.
Using detect-secrets (Yelp)
# Install detect-secrets
pip install detect-secrets
# Create a baseline (existing secrets to ignore)
detect-secrets scan > .secrets.baseline
# Add pre-commit hook
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 the pre-commit hook
pre-commit install
Using git-secrets (AWS)
# Install git-secrets
brew install git-secrets
# Initialize in your repository
cd /path/to/repo
git secrets --install
git secrets --register-aws
# Add custom patterns
git secrets --add 'sk_live_[a-zA-Z0-9]{24}'
git secrets --add 'ghp_[a-zA-Z0-9]{36}'
# Scan existing history
git secrets --scan-history
What to Do When You Find a Secret
- Revoke the secret immediately. Go to the provider's console and disable the key. Do not wait until you have cleaned up the repository.
- Generate a new secret. Create a replacement and update your application configuration.
- Remove the secret from git history. Use BFG Repo-Cleaner (faster) or git filter-repo:
# Using BFG Repo-Cleaner
java -jar bfg.jar --replace-text passwords.txt repo.git
cd repo.git
git reflog expire --expire=now --all
git gc --prune=now --aggressive
# Using git filter-repo
git filter-repo --invert-paths --path config/secrets.yml
- Force push the cleaned history. All collaborators must re-clone the repository after history rewriting.
- Audit access logs. Check the provider's logs for unauthorized usage during the exposure window.
- Implement prevention. Add pre-commit hooks and CI/CD scanning to prevent recurrence. Move secrets to a proper secrets manager. See our guide on securing environment variables.
Building a Complete Secret Detection Strategy
No single tool catches everything. Build a layered defense:
- Layer 1: IDE plugins that highlight secrets as you type (GitLens, detect-secrets VS Code extension)
- Layer 2: Pre-commit hooks (detect-secrets, git-secrets) that block commits containing secrets
- Layer 3: CI/CD pipeline scanning (Gitleaks GitHub Action) that catches secrets that bypass pre-commit hooks
- Layer 4: GitHub secret scanning with push protection for known patterns
- Layer 5: Regular full-history scans (TruffleHog) to catch secrets from before scanning was implemented
- Layer 6: Web surface scanning (SecureBin Exposure Checker) to catch secrets exposed through web server misconfigurations
Frequently Asked Questions
Does making a repository private remove the risk of exposed secrets?
No. Private repositories reduce the attack surface but do not eliminate it. Anyone with read access to the repository (employees, contractors, CI/CD systems) can see the secrets. If a private repository is accidentally made public even briefly, all secrets in its history are exposed. Additionally, GitHub Advanced Security is required for secret scanning on private repos. Treat private repositories as "less exposed" not "secure."
How do I handle secrets that were committed months ago?
First, revoke and rotate the secret. Then use TruffleHog to scan the full git history and identify all exposed secrets. Use BFG Repo-Cleaner to remove them from history. Even if a secret has been in the repository for months without incident, it should still be rotated because you cannot know whether it was accessed by unauthorized parties. Finally, implement pre-commit hooks and CI/CD scanning to prevent future leaks.
Which tool should I start with?
Start with Gitleaks for CI/CD integration because it is fast, easy to configure, and has excellent GitHub Actions support. Add detect-secrets as a pre-commit hook for local development. Use TruffleHog for periodic full-history scans of your organization. For web-facing secrets (exposed .env files, config files), run the SecureBin Exposure Checker weekly. This combination covers the most common secret exposure vectors.
Secrets Leak Through More Than Git
Exposed .env files, backup files, and debug endpoints on your web server can leak credentials too. Check your domain with SecureBin Exposure Checker.
Scan Your Domain FreeThe Bottom Line
Secret detection is not optional. With 12.8 million secrets leaked annually on GitHub alone, the question is not whether your organization will commit a secret, but when. The combination of pre-commit hooks, CI/CD scanning, and regular full-history audits creates a safety net that catches secrets before they become breaches. Start with one tool today and build your detection layers over time.
Related reading: How to Check if API Key is Exposed, How Hackers Find Exposed API Keys, Secure Environment Variables in Production, How to Secure API Keys in Code.