How to Check for Exposed API Keys
Find leaked secrets before attackers do
TL;DR
TL;DR: Search your codebase with grep for common key patterns. Check git history for past commits. Inspect your browser bundle and network requests. Use automated tools like GitHub secret scanning or CheckYourVibe for continuous monitoring.
Common Key Patterns to Search For
Most API keys follow a recognizable prefix. If you see these strings in source files, DevTools, or network logs, you're looking at a real credential:
| Service | Pattern | Example |
|---|---|---|
| Stripe Secret | sk_live_ or sk_test_ | sk_test_51H... |
| OpenAI | sk- | sk-proj-abc123... |
| Supabase Service | eyJ (JWT) | eyJhbGciOiJIUz... |
| AWS | AKIA | AKIAIOSFODNN7... |
| GitHub Token | ghp_ or github_pat_ | ghp_xxxx... |
| SendGrid | SG. | SG.xxxx... |
| Twilio | SK (32 chars) | SKxxxx... |
Method 1: Search Your Source Code
Use grep to search for hardcoded keys in your project:
# Search for common key patterns
grep -rn "sk_live\|sk_test\|sk-\|AKIA\|ghp_\|SG\." \
--include="*.ts" --include="*.js" --include="*.tsx" --include="*.jsx" .
# Search for generic patterns
grep -rn "api_key\|apiKey\|API_KEY\|secret\|password" \
--include="*.ts" --include="*.js" --include="*.json" .
# Exclude node_modules and other irrelevant directories
grep -rn "sk_live" --include="*.ts" --exclude-dir=node_modules .
Pro tip: Look for long random strings (32+ characters) that aren't obviously UUIDs or hashes.
Method 2: Check Git History
A key you deleted from a file last week might've been committed to git before the deletion. It's still in every clone of that repo.
# Search entire git history for key patterns
git log -p --all | grep -E "sk_live|sk_test|api_key|AKIA"
# Search for specific file changes
git log -p -- .env
# Check if .env files were ever tracked
git log --all --full-history -- "*.env*"
# See all .env related commits
git log --oneline --all -- ".env*"
Finding a key in git history means it's compromised. Rotate it before anything else, even if the repo is private. Private repos get forked, cloned, and occasionally made public by accident. Clean the history after you're safe, not before.
Method 3: Inspect Your Browser Bundle
If a secret key ends up in your client-side JavaScript, every visitor to your site can read it. Check your production build:
# Build your app
npm run build
# Search the build output
grep -rn "sk_live\|sk_test\|sk-\|STRIPE_SECRET" .next/ dist/ build/
# For Next.js specifically
grep -rn "sk_" .next/static/
Check in the Browser
- Open your deployed site
- Open DevTools (F12) → Sources tab
- Press Ctrl+Shift+F (or Cmd+Shift+F on Mac) to search all sources
- Search for
sk_,api_key, or other patterns
Method 4: Monitor Network Requests
Your browser shouldn't be calling third-party APIs directly with secret keys. Open DevTools, go to the Network tab, and use your app normally: log in, submit forms, trigger the key workflows.
Click on each request and check the Headers and Payload tabs. If you see Authorization: Bearer sk_live_... or a raw API key in a request body going to an external service, the key is visible to every user on your network.
Secret keys in browser requests are readable by anyone who can run DevTools or intercept traffic on the same network. This isn't a theoretical risk.
Method 5: Use Automated Tools
GitHub Secret Scanning
Enable in repo Settings → Security → Secret scanning. GitHub will alert you when it detects exposed secrets.
Pre-commit Hooks
Install tools that scan before each commit:
# Install detect-secrets
pip install detect-secrets
# Create baseline
detect-secrets scan > .secrets.baseline
# Add pre-commit hook
# In .pre-commit-config.yaml:
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
CI/CD Scanning
Add secret scanning to your deployment pipeline:
# GitHub Actions example
- name: Scan for secrets
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: main
head: HEAD
What to Do If You Find Exposed Keys
Rotate first. Everything else is secondary.
- Rotate immediately: generate a new key in the service dashboard
- Deploy it: update the environment variable and redeploy
- Revoke the old key: delete it; don't leave it active "just in case"
- Check for abuse: review the service's usage logs for the window the key was exposed
- Fix the root cause: move to server-side environment variables, add
.envto.gitignore, add a pre-commit hook
Are Supabase anon keys safe to have in client code?
Yes, when Row Level Security is enabled. The anon key is designed to be in your client code. It only permits what your RLS policies allow. The service_role key is a different story. That one bypasses RLS entirely and must never appear in client JavaScript.
What about Firebase config objects?
Firebase's apiKey is intentionally public. It just tells the SDK which project to connect to. What protects your data is Firebase Security Rules. Hiding the config doesn't help; writing good rules does.
How often should I check for exposed keys?
Set up automated scanning so every commit gets checked. Beyond that, do a manual pass before major releases and when new people join the team. That's when new credentials tend to appear.
Related guides:How to Hide API Keys · How to Rotate API Keys · How to Enable Secret Scanning