Your API key is probably sitting in your JavaScript
Anything your browser downloads can be read by anyone. Here is how AI-built apps leak OpenAI, Stripe and Supabase keys, and how to fix it in ten minutes.
When you build an app with an AI tool, it is very easy to end up with a secret key inside the code that gets sent to every visitor. You do not see it, because the app works. A stranger opening the browser tools sees it in seconds.
Why it happens
Your site is made of files that the browser downloads and runs. Anything inside those files is public. If the AI wrote const openai = new OpenAI({ apiKey: "sk-proj-..." }) in a page component, that key is now part of a JavaScript file anyone can open.
Two things make this worse in tools like Lovable, Bolt and Cursor:
- Variables with a special prefix are copied into the browser on purpose. In Vite apps that prefix is
VITE_, in Next.js it isNEXT_PUBLIC_. Putting a secret behind one of those prefixes publishes it. - The AI often takes the shortest path to “it works”, which means calling the paid service straight from the page.
Which keys are dangerous
Not every key is a problem. Some are meant to be public:
- The Supabase anon (publishable) key is designed for the browser, as long as your database has Row Level Security turned on.
- Firebase web config values are public by design.
These are never safe in the browser:
- OpenAI, Anthropic and other AI keys: someone else runs up your bill.
- Stripe secret keys (
sk_live_...): full access to your payments account. - The Supabase service_role key: it skips every database rule.
- GitHub tokens, AWS keys, private keys.
How to check
Open your live site, open the browser developer tools, go to Sources, and search all files for sk-, sk_live, service_role and BEGIN PRIVATE KEY. Or paste a file into our free secret checker, which runs in your browser and uploads nothing. Greenlight Scan does this for all your JavaScript files at once.
How to fix it
- Rotate the key first. Create a new key at the provider and delete the old one. Assume the old one has been copied.
- Move the code that uses the key to the server: an API route, a serverless function or a Supabase Edge Function.
- Have the page call your own endpoint instead of the paid service.
- Store the new key as a server-side environment variable, without a
VITE_orNEXT_PUBLIC_prefix. - Re-scan to confirm the key is gone from your bundle.
You can paste this into your AI tool: “Find every place a secret API key is used in client-side code. Move that call into a server-only function and make the page call that function instead. Never put secret keys in variables starting with VITE_ or NEXT_PUBLIC_.”
Removing the key from the code is not enough on its own. If it was ever live on the internet, the only safe key is a new one.
Check your own app in about 2 minutes.
Scan my app freeThe Friday leak report
One short email a week: the newest ways AI-built apps leak data, and the one-line fix for each. No spam, unsubscribe any time.