Stop Leaking API Keys: A Vibe Coder's Guide to Secrets
A leaked secret key is the closest thing to handing an attacker your wallet. Stripe charges, OpenAI bills, AWS spend — all on your dime. The frustrating part is that most leaks come from one well-meaning shortcut an AI assistant takes to make the code run.
Publishable vs. secret: know which is which
Many services ship two keys. The publishable / public key (Stripe `pk_`, Supabase anon, Firebase config) is *designed* to live in the browser. The secret key (Stripe `sk_`, OpenAI `sk-`, AWS secret, Supabase service_role) must never leave your server. Leaking the first is fine; leaking the second is an incident.
Where keys actually leak
The client bundle. Anything imported into front-end code ships to the browser. In Next.js, only `NEXT_PUBLIC_`-prefixed vars are exposed — but AI assistants sometimes add that prefix to a secret to silence an `undefined` error. That one prefix publishes it.
Git history. A key committed once lives forever in history, even after you delete the line. Scanners crawl public GitHub constantly.
API responses and error pages. Verbose error output and debug endpoints sometimes echo environment variables straight to the client.
The rule that prevents almost all of it
Any call that uses a secret key should run on your server — an API route, edge function, or backend — and the browser calls *that*, never the third party directly. The secret stays in a server-only environment variable (no public prefix) and in your hosting provider's encrypted env settings, never in the repo.
If you've already leaked one
Rotate it immediately in the provider dashboard — assume the old one is compromised. Removing it from your code is not enough; it's already in Git history and possibly already scraped. Then move the new key server-side. For a wider sweep, see The 7 Most Common Security Holes.