Home / Errors / Vibe coding (any tool) / api-key-in-frontend

The AI put your API key in the frontend: OpenAI, Stripe, or Supabase keys visible in the JS bundle

Vibe coding (any tool) Moderate 30-60 minutes security critical Last verified Jul 17, 2026
The fix  Treat the key as compromised right now: revoke and rotate it in the provider dashboard before touching code. Removing it from the bundle does not un-leak it. Then move the API call behind a server endpoint (Next.js API route, edge function, or small proxy) that holds the secret in a server environment variable, and add auth so the proxy isn't a free relay.

Symptoms

  • View-source or the DevTools Network tab shows your raw OpenAI, Stripe, or service-role key in the shipped JavaScript
  • Mystery usage on your account, or your quota is suddenly exhausted
  • A surprise bill: one documented case ran to $14,000 on OpenAI after attackers found an exposed key and maxed out usage
  • A secret-scanning alert email lands in your inbox

Why it happens

AI pattern-matches quick-start examples

Asked to 'call the OpenAI API from my app', AI tools reproduce tutorial code, which puts the secret key directly in client code. Quick-starts are written for local experiments, not production, and the model does not know the difference.

Frontend-only platforms have nowhere else to put the key

On vibe platforms with no backend, the key has nowhere else to live, so it ships in the bundle by construction. Any working integration on such a platform is a leaking one.

This failure is systemic, not rare

Escape.tech scanned 5,600+ vibe-coded apps and found 400+ exposed secrets in frontend bundles. Wiz Research found systemic risks in roughly 20% of organizations building on vibe-coding platforms, including hardcoded OpenAI keys and service-account credentials in client-side JavaScript.

How to fix it

  1. Rotate the key first (this is the security-critical step)Treat any key that ever shipped in a bundle as compromised. Revoke and rotate it immediately in the provider dashboard. Removing it from the code does not un-leak it; assume it has already been scraped.
  2. Move the API call server-sidePut the call behind a Next.js API route, a Supabase Edge Function, or a small backend proxy. The secret lives in a server environment variable, and the browser only ever talks to your endpoint.
  3. Add auth to the proxyAn open proxy is just a free relay for your key. Require a session or token before the endpoint will spend your money. Missing auth and missing rate limiting compound this exact failure, so close both.
  4. Know which keys are allowed client-sideOnly intentionally public values belong in the browser: Stripe publishable keys, Firebase web config, and the Supabase anon key (safe only with RLS enabled). Anything named 'secret', 'service', or 'private' is server-only.
  5. Cap the damage for next timeSet hard spend caps and budget alerts on every paid API, and add secret scanning (GitHub push protection, gitleaks, GitGuardian) so a regenerated key never ships again.

How to prevent it

  • Never put a secret in any file the frontend imports; secrets live in server environment variables only.
  • When wiring any paid API, ask the AI explicitly for a server-side proxy pattern, then verify where the key ends up.
  • Run secret scanning (GitHub push protection, gitleaks, or GitGuardian) on every commit.
  • Set spend caps and billing alerts before launch, not after the first scary invoice.
  • Periodically search your shipped JS bundle for provider key names and the word 'secret'.

Tools that actually fix this

Recommended because they address the failure mode above, not because of the payout. Some are affiliate links; see how we choose.

Frequently asked questions

Is it safe to put an API key in a React app?

No secret key is safe in a React app or any frontend code: everything in the JavaScript bundle is readable by anyone with DevTools. The only values that belong client-side are intentionally public ones, such as Stripe publishable keys, Firebase web config, and the Supabase anon key with RLS enabled. Secret keys for OpenAI, Stripe, or a Supabase service role must stay on a server.

I deleted the exposed API key from my code. Am I safe now?

No. A key that ever shipped in a bundle must be treated as compromised, because scrapers may already have copied it. Revoke and rotate the key in the provider dashboard first, then move the API call behind a server endpoint so the new key never appears in client code.

How much damage can an exposed API key actually do?

A lot, and quickly. One documented case ran to a $14,000 OpenAI bill after attackers found an exposed key and maxed out usage. Escape.tech found 400+ exposed secrets while scanning 5,600+ vibe-coded apps, so attackers actively hunt for exactly this. Spend caps and billing alerts limit the blast radius when prevention fails.

How do I call the OpenAI API from my app without exposing the key?

Route the request through your own server: a Next.js API route, a Supabase Edge Function, or a small backend proxy. The secret key lives in a server environment variable, the browser calls your endpoint, and your endpoint calls OpenAI. Add authentication and rate limiting to that endpoint so it cannot be abused as a free relay for your key.

Sources

Related errors

The Vibe Oops briefing

One email when something ships to production that should not have. New incidents, new error guides, no filler.