Leaked secrets are the most expensive mistake in vibe-coded apps. Bots scan public GitHub commits and popular hosting domains around the clock for strings like sk- and AKIA, and a working OpenAI or AWS key can be abused within minutes. Here is how to find out if you are exposed, and what to do if you are.
Where secrets leak
- A committed .env file.
.gitignorewas missing, or was added after the first commit. - Hardcoded in source. The AI pasted the key straight into
openai.tsto "make it work". - The frontend bundle. Variables prefixed
NEXT_PUBLIC_,VITE_,REACT_APP_orEXPO_PUBLIC_are inlined into JavaScript that every visitor downloads. Putting a secret in one of these publishes it. - A publicly served .env. A misconfigured server or static export serves
/.envas a file. - Git history. You removed the key in a later commit, but the old commit is still there.
- Logs, screenshots, issue trackers and chats you shared while debugging.
How to check
Your repository and its history
# Is a .env tracked right now?
git ls-files | grep -i "\.env"
# Was one ever committed?
git log --all --oneline -- .env '*.env' '.env.*'
# Scan the entire history for secrets
npx gitleaks detect --source . -v
# or
docker run --rm -v "$PWD:/repo" trufflesecurity/trufflehog git file:///repo
On GitHub, also turn on Secret scanning and Push protection (Settings → Code security). They are free for public repos.
Your live site
curl -s -o /dev/null -w "%{http_code}\n" https://yourapp.com/.env # should be 404
curl -s https://yourapp.com | grep -oE 'src="[^"]+\.js"' # list bundles
curl -s https://yourapp.com/assets/index-abc123.js | grep -oE "sk-[A-Za-z0-9_-]{20,}|sk_live_[A-Za-z0-9]+|AKIA[0-9A-Z]{16}|service_role"
Or let ShipCheck do it. Paste your URL or public repo and it checks for exposed .env files, scans the HTML and JavaScript you ship plus repo files for common key formats, and masks anything it finds so the report doesn't leak it again.
Found one? Rotate first, clean up second
Order matters. Removing the key from code does nothing to stop someone who already copied it. Make the old key useless first.
- Create a new key in the provider's dashboard.
- Update it everywhere it is used: your host's environment variables (Vercel, Netlify, Railway, Supabase Edge Function secrets), CI, and local
.env. Redeploy. - Revoke the old key. Do this right away for high-risk keys, even if it causes a few minutes of downtime.
- Check usage and billing for activity you don't recognise, and contact the provider if there was abuse.
Where to rotate common keys:
- OpenAI: platform.openai.com → API keys → create new, then delete the old one. Set a monthly budget limit.
- Anthropic: console.anthropic.com → API Keys.
- Stripe: Dashboard → Developers → API keys → "Roll key" on the secret key. Also roll webhook signing secrets if they leaked.
- Supabase: Project Settings → API. Leaked
service_roleor secret keys bypass RLS and are critical. Use the dashboard's key rotation (newer projects use rotatable secret keys; older JWT-based keys rotate by rolling the JWT secret, which also signs out users). Rotate the database password if it leaked. - AWS: IAM → user → Security credentials → create a new access key, deactivate the old one, then delete it. Review CloudTrail.
- GitHub tokens: Settings → Developer settings → revoke and regenerate.
- Resend, SendGrid, Twilio: API keys page, then revoke and create a new one.
Optional: purge it from history
After rotating, you can rewrite history with git filter-repo --path .env --invert-paths or BFG Repo-Cleaner and then force-push. This is cosmetic once the key is dead, and it breaks other people's clones, so coordinate with collaborators. Never skip rotation because you rewrote history.
Prevent it next time
.gitignorecontaining.env,.env.*and!.env.example, committed before your first real secret.- Secrets only in server code: API routes, server actions, Edge Functions. Never in a
NEXT_PUBLIC_orVITE_variable. - A pre-commit hook:
gitleaks protect --staged. - GitHub push protection on.
- Per-environment keys with the minimum scope and spending caps.
- A scan before every launch.