Secret Keys in Your Frontend: Find and Fix Them Today

AI-built apps often ship API keys inside their JavaScript. Which keys are safe to expose, how to find the ones that aren’t, and the order to fix them in.

On this page · 4 sections
  1. How common are leaked keys in AI-built apps?
  2. Which keys are safe in the browser?
  3. How do you find exposed keys?
  4. What do you do when you find one?

Key takeaways

  • Anything in your app’s frontend is public, including every API key bundled into its JavaScript. A security firm found more than 400 exposed secrets while scanning 5,600 AI-built apps.
  • Some keys are designed to be public (Supabase publishable, Stripe publishable). Others must never reach the browser (Supabase secret, Stripe secret, OpenAI and other paid APIs).
  • If a secret key was ever in your frontend, rotate it first, then move the call it powers to the server.

Every AI app builder makes the same trade-off: the fastest way to make a feature work is to call the service straight from the browser. That works, and it also puts the key for that service in the JavaScript that every visitor downloads. Anyone who opens the browser’s developer tools can copy it.

This post covers which keys are safe to expose, how to find the ones that aren’t, and what to do when you find one. It is part of the guide to making an AI-built prototype ready for real users; for database access rules, see Supabase RLS: is your AI-built app leaking data?

How common are leaked keys in AI-built apps?

Very. Escape, a security company, scanned 5,600 apps built with AI coding tools and reported more than 2,000 highly critical vulnerabilities, more than 400 exposed secrets and 175 cases of exposed personal data, including bank account details (Escape).

The cause is structural. Build tools inline environment variables with a public prefix into the JavaScript at build time. Vite’s documentation warns that VITE_ variables “should not contain sensitive information such as API keys” because “the values of these variables are bundled into your source code at build time” (Vite). Next.js does the same with the NEXT_PUBLIC_ prefix (Next.js). An AI tool that adds the prefix to make an error go away has just published the key.

Which keys are safe in the browser?

KeySafe in the frontend?Why
Supabase publishable (anon) keyYes, with RLS on every tableIt only identifies the project; policies decide what it can reach
Supabase secret (service role) keyNeverIt bypasses every row-level security policy
Stripe publishable key (pk_…)YesIt is meant for the browser and can’t read your account or move money on its own
Stripe secret key (sk_…)NeverIt can create charges, refunds and read all payment data
OpenAI, Anthropic and other AI API keysNeverAnyone can spend your credit with it
Email, SMS and database connection stringsNeverAnyone can send as you or read your data

Supabase is explicit about the second row: “A leaked secret key exposes all of your project’s data,” and secret keys “bypass every Row Level Security policy you have. Never put one in a browser, a shipped application, or source control” (Supabase).

How do you find exposed keys?

Search the live site. Open your app, open the browser’s developer tools, go to the Sources (or Debugger) tab and search all files for sk_, service_role, secret, api_key, token and the names of the services you use. Also check the Network tab: a request that goes from the browser straight to a paid API is carrying its key.

Search the code and its history. Look for environment variables with a public prefix (VITE_, NEXT_PUBLIC_, EXPO_PUBLIC_) that hold anything other than public identifiers. Then search the git history, not just the current files: a key that was committed and later deleted is still in the history, and still valid.

Turn on secret scanning. If the code is on GitHub, enable secret scanning and push protection on the repository. It flags known key formats in commits and blocks new ones from being pushed.

What do you do when you find one?

Work in this order:

  1. Rotate the key. Create a new key in the provider’s dashboard and revoke the old one. Assume the old key has been copied; you have no way to know it hasn’t.
  2. Check the damage. Look at the provider’s usage and logs since the key was exposed: unexpected AI API spend, emails you didn’t send, database reads from unknown places.
  3. Move the call to the server. The browser calls your server (a Supabase Edge Function, a Next.js route handler, any small backend), and only the server holds the key. The server also decides who is allowed to make the call and how often.
  4. Add limits. Set spending caps or budget alerts on paid APIs and rate limits on your own endpoints, so a future mistake costs little.

Step 3 is the one AI tools skip, because it needs a server-side piece the prototype didn’t have. It is usually a small change: one function per external service.

Frequently asked questions

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

Only if the key is designed to be public, like the Supabase publishable key or Stripe’s publishable key. Anything with a VITE_ or NEXT_PUBLIC_ prefix ends up in the JavaScript sent to every visitor, so secret keys must stay on the server.

What happens if my OpenAI API key is exposed?

Anyone who copies it can make requests billed to your account until you revoke it. Revoke and replace the key, check your usage for unexpected spend, and move the calls to a server endpoint that holds the new key.

Does deleting a key from the code fix a leak?

No. The key is still valid, still in your git history and possibly already copied. Rotate it in the provider’s dashboard first; removing it from the code comes after.

Sources

  1. Escape — The state of security of vibe-coded apps
  2. Vite — Env variables and modes
  3. Next.js — Environment variables
  4. Supabase — Understanding API keys
AIAPI keysSecuritySupabase

Filipe Eduardo

Senior Software Engineer. Seven years building web and mobile products end to end and leading the teams that ship them.

Follow along

Want to talk
about this?

I work on problems like this every day. Tell me about yours.

Get in touch