Somewhere in your codebase, there's probably a secret that shouldn't be there.
An API key. A database password. An AWS credential. A Stripe token.
You didn't mean to commit it. Maybe you were testing something. Maybe you copied an example file. Maybe the AI coding assistant generated it and you didn't notice.
It doesn't matter how it got there. What matters is finding it before someone else does.
According to GitGuardian's 2026 State of Secrets Sprawl report, 35% of private repositories contain at least one exposed secret. Attackers actively scan GitHub for these, and they find them within minutes of being pushed.
Why Exposed Secrets Are So Dangerous
They're Easy to Find
Attackers use automated tools that scan every public commit on GitHub in real-time. They search for patterns like:
AKIA(AWS access key prefix)sk_live_(Stripe live key prefix)ghp_(GitHub personal access token prefix)mongodb+srv://connection stringspostgres://connection strings
If you push a secret to a public repo, assume it's compromised within minutes.
They Never Really Disappear
Deleting a file doesn't delete history. That API key you committed 6 months ago? It's still in your git history. Every fork still has it. Every clone still has it.
Even if you rotate the credential immediately, anyone who cloned your repo before the rotation can access the old secret.
The Blast Radius Is Huge
One exposed AWS key can:
- Spin up crypto mining instances (you pay the bill)
- Access your databases
- Delete your infrastructure
- Pivot to other connected services
One exposed database credential can:
- Dump all user data
- Inject malicious data
- Delete everything
- Hold you ransom
Where Secrets Hide
The Obvious Places
.envfiles committed to gitconfig.jsorsettings.pywith hardcoded valuesdocker-compose.ymlwith embedded credentials- CI/CD config files (
.github/workflows/,.gitlab-ci.yml)
The Sneaky Places
- Test files: Developers often use real credentials for integration tests
- Mock data: That "example" API key might actually be real
- Comments: "TODO: remove this before production" (narrator: they didn't)
- Old branches: Secrets cleaned from main but still in feature branches
- Git history: Deleted files live forever in
.git/
The AI-Generated Places
AI coding tools frequently generate code with placeholder secrets that look real:
// AI generated this as an "example"
const apiKey = "sk_live_51H7bKLM2eZvKYlo2C...";
If that pattern matches a real key format, security scanners will flag it, and attackers will try it. This is one reason why AI-generated code needs careful review.
How to Scan Your Repository
Method 1: Automated Security Scan (Fastest)
The fastest way to find exposed secrets is an automated scan that checks:
- All files in your repository
- Your entire git history
- Common secret patterns
- Environment file leaks
Scan for exposed secrets now
Get a security scan that checks for API keys, credentials, and .env files in under 3 minutes. Free for public repos.
Scan Your Repo →Method 2: GitHub Secret Scanning (If Enabled)
GitHub has built-in secret scanning for public repos and GitHub Advanced Security subscribers:
- Go to your repository → Settings → Security
- Check if "Secret scanning" is enabled
- View alerts under Security → Secret scanning alerts
Limitations:
- Only detects secrets from partner patterns (Stripe, AWS, etc.)
- Doesn't catch custom secrets or generic passwords
- Doesn't scan git history by default
Method 3: Git-Secrets (Command Line)
AWS's git-secrets tool scans for AWS credentials:
# Install
brew install git-secrets
# Scan current directory
git secrets --scan
# Scan entire history
git secrets --scan-history
Limitations:
- AWS-focused by default
- Requires manual setup for other patterns
- No visual report
Method 4: TruffleHog (Deep History Scan)
TruffleHog scans your entire git history for high-entropy strings:
# Install
pip install truffleHog
# Scan
trufflehog git https://github.com/your/repo
Limitations:
- High false positive rate
- Entropy-based detection misses low-entropy secrets
- Command line output can be overwhelming
What to Do When You Find a Secret
Step 1: Don't Panic (But Move Fast)
You have a window (maybe hours, maybe days) before an attacker finds it. Use that time wisely.
Step 2: Rotate the Credential Immediately
Before doing anything else, generate a new credential and invalidate the old one:
| Service | How to Rotate |
|---|---|
| AWS | IAM → Users → Security credentials → Create new key, delete old |
| Stripe | Dashboard → Developers → API keys → Roll keys |
| GitHub | Settings → Developer settings → Personal access tokens → Regenerate |
| Database | Create new user/password, update connection strings, delete old user |
Step 3: Update Your Code
Replace the hardcoded secret with an environment variable:
// Before (BAD)
const apiKey = "sk_live_51H7bKLM2eZvKYlo2C...";
// After (GOOD)
const apiKey = process.env.STRIPE_SECRET_KEY;
Step 4: Check for Damage
Review logs for the compromised service:
- Unusual API calls?
- Unexpected charges?
- Data access from unknown IPs?
- New users or resources created?
Step 5: Clean Git History (Optional but Recommended)
Removing the secret from history prevents future exposure:
# Using git filter-branch (built-in but slow)
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch path/to/secret-file" \
--prune-empty --tag-name-filter cat -- --all
# Force push (destructive!)
git push origin --force --all
Force pushing rewrites history. Coordinate with your team first. Anyone with an old clone will have conflicts.
How to Prevent Secret Leaks
1. Use Environment Variables
Never commit secrets. Always use environment variables:
# .env.local (in .gitignore)
DATABASE_URL=postgres://user:pass@host:5432/db
STRIPE_KEY=sk_live_...
// In your code
const dbUrl = process.env.DATABASE_URL;
2. Add Secrets to .gitignore
Before creating any secrets files:
# .gitignore
.env
.env.local
.env.*.local
*.pem
*.key
credentials.json
3. Use Pre-Commit Hooks
Block commits that contain secrets:
# Install pre-commit
pip install pre-commit
# Add to .pre-commit-config.yaml
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
4. Use a Secrets Manager
For production, don't even put secrets in environment variables on disk. Use:
- AWS Secrets Manager
- HashiCorp Vault
- Doppler
- 1Password Secrets Automation
These inject secrets at runtime without ever writing them to disk. For a complete security posture, combine secrets management with regular codebase audits.
5. Scan on Every PR
Add secret scanning to your CI/CD pipeline. Catch secrets before they merge:
# .github/workflows/security.yml
name: Security Scan
on: [pull_request]
jobs:
secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Scan for secrets
uses: trufflesecurity/trufflehog@main
Common Mistakes to Avoid
"It's a Private Repo, We're Fine"
Private repos get breached. Employees leave. Laptops get stolen. CI/CD systems get compromised. Treat secrets in private repos with the same care as public ones.
"I Deleted the File"
Git remembers everything. Deleted files exist in history until you rewrite it.
"It's Just a Test Key"
Is it? Are you sure? Many "test" keys have production access. Verify before assuming.
"I'll Fix It Later"
You won't. Fix it now. Set a calendar reminder if you must. Exposed secrets don't wait for your sprint planning.
Frequently Asked Questions
How quickly do attackers find exposed secrets?
Minutes. Automated scanners watch GitHub's public event stream in real-time. Within 5 minutes of pushing a valid AWS key, you may see unauthorized API calls.
What if the secret was only exposed briefly?
Assume it's compromised. Rotate it. The "brief" exposure was long enough for automated scanners to capture it.
Should I report the incident?
Depends on what was exposed. If user data could have been accessed, you may have legal notification requirements (GDPR, CCPA, etc.). Consult your legal team.
How do I know if my secret was actually used?
Check the service's logs and audit trails. AWS CloudTrail, Stripe Dashboard, GitHub audit logs. Most services track API usage.
Exposed secrets are one of the most common and most preventable security issues in modern codebases. A single scan can find them. A few hours of work can fix them.
The question isn't whether you have exposed secrets. The question is whether you've looked.
Related reading:
- Code Audit Checklist: Complete security and code quality checklist
- What Is Technical Due Diligence?: Security issues are the #1 deal-killer in due diligence
- I Just Inherited a Codebase. Now What?: First steps when taking over unfamiliar code
Find your exposed secrets
Security scan, architecture map, and AI readiness grade. Free for public repos. Results in 3 minutes.
Scan Your Repo Free →