UnbreakMyApp / Fix guides

Secret API key exposed in your frontend code

OpenAI, Stripe secret or Supabase service_role keys in browser code can be stolen by anyone. How to find, rotate and move them to the server.

Why it happens

Everything your browser downloads (JavaScript, environment variables bundled into it) is visible to anyone using DevTools. In Vite apps (which Lovable uses), any variable starting with VITE_ is baked into the public bundle.

Public keys like the Supabase anon/publishable key or Stripe publishable key (pk_...) are fine there. Secret keys are not: Stripe sk_..., Supabase service_role or secret keys, OpenAI/Anthropic/other AI keys, email or SMS provider keys.

A leaked secret key can mean someone runs up your AI bill, refunds or charges through your Stripe account, or reads your whole database.

How to fix it, step by step

  1. Open your live site → DevTools → Sources, and search (Ctrl+Shift+F) for sk_, service_role, sk-, or "secret". Also search your code and .env files.
  2. Rotate any exposed secret first: create a new key in the provider dashboard and revoke the old one. Removing it from code is not enough once it has been public.
  3. Move the new key to server-side secrets only (e.g., Supabase → Edge Functions → Secrets). Do not put it in a VITE_ variable.
  4. Create an Edge Function that performs the secret action (call the AI API, create a Stripe session) and call it from the frontend with supabase.functions.invoke().
  5. Inside the function, check the user is logged in and add basic limits so it cannot be abused.
  6. Check usage dashboards (OpenAI, Stripe, etc.) for activity you did not expect.

Paste-ready prompt for Lovable

Find and remove secret keys from my frontend:
1. Search the entire codebase for API keys and secrets (sk_, sk-, service_role, secret, api_key) and list where each appears. Ignore public keys like the Supabase anon/publishable key and Stripe pk_.
2. For each secret, create a Supabase Edge Function that does the server-side work, reading the key from Deno.env.get() (I will add the secret in Supabase).
3. Replace frontend calls with supabase.functions.invoke().
4. In each function, require a logged-in user and add a simple rate limit.
5. Remove the secrets from all VITE_ variables and code.
Tell me which keys I must rotate.

FAQ

Is my Supabase anon key a secret?

No. It is designed to be public, as long as RLS is on. The service_role / secret key must never be in the browser.

I deleted the key from the code. Am I safe?

No. Copies may exist in old deploys, git history or someone's logs. Rotate it.

Still broken?

Get a free diagnosis by email within 24 hours. Fixed or refunded.

Get a free diagnosis

Or join the waitlist for updates:

Sources