Exposed API key in your JavaScript

Anything in your frontend bundle is public. Minifying does not hide it. If an AI tool put an OpenAI, Stripe secret, or other private key into client code, anyone can copy it from their browser and use it on your bill.

Run a free scan

How it usually happens

  • A prompt like "call OpenAI from this button" puts the API call, and the key, in a React component.
  • An environment variable with a public prefix (VITE_, NEXT_PUBLIC_) is bundled into the browser build.
  • A key pasted into a config file during testing never gets moved.

How to find it

Open your live site, open developer tools, and search all loaded scripts for common key prefixes such as "sk-", "sk_live_", "re_" or the word "secret". RowLocked's free scan does this automatically across your JS bundles and masks anything it finds in the report.

How to fix it

  • Rotate the key first. Once it has been public, assume it is compromised.
  • Move the call into a server route or a Supabase edge function, and keep the key in server-side environment variables.
  • Have the server check who is calling, and add a rate limit, before it calls the paid API.
Move every call to a paid or private API out of frontend code into a Supabase edge function (or server route). Read the key from a server-side secret, never a VITE_ or NEXT_PUBLIC_ variable. Require a signed-in user and add a simple rate limit in the function.

Questions

Is a Supabase anon key or Stripe publishable key a problem?

No, those are designed to be public. Secret keys, service_role keys and most AI provider keys are the ones that must stay server-side.

More guides

Check my app now