How to find leaked API keys in your website's JavaScript (and fix them)

A practical guide to finding secret API keys exposed in client-side JavaScript, telling public keys from secret ones, and moving API calls to the server safely.

By Wardzo Team · Updated · 2 min read · Security

Free · no signup · passive checks only · results in under a minute

If your website calls an AI API, a payment API or a cloud service directly from the browser, the key that authorises that call is in your JavaScript. Anyone can read it. This guide shows how to find such keys, decide which ones matter and fix the problem properly.

Why this happens so often

Front-end frameworks bundle environment variables into the browser code when they are prefixed for public use, for example NEXT_PUBLIC_, VITE_ or REACT_APP_. AI coding tools often reach for these prefixes because they make the code work immediately. The result works, and it also publishes the key.

Public keys vs secret keys

Not every key in JavaScript is a leak. Some are designed to be public:

Key Safe in the browser?
Stripe publishable key (pk_live_…) Yes
Stripe secret key (sk_live_…) or restricted key (rk_live_…) No
Supabase anon key, with Row Level Security enabled Yes
Supabase service_role key No, it bypasses Row Level Security
Google Maps or Firebase browser key, restricted by referrer Yes, if restricted
OpenAI (sk-…) or Anthropic (sk-ant-…) keys No
AWS access key ID (AKIA…) with its secret No

Rule of thumb: if the key can spend money, send email, or read or write private data without any other check, it must never reach the browser.

How to find leaked keys

Option 1: automated scan

Run a free leaked API key check. Wardzo loads your pages, collects the JavaScript files they reference and matches known key formats. Results are masked.

Option 2: manually in DevTools

  1. Open your site, then DevTools, then the Sources (Chrome) or Debugger (Firefox) tab.
  2. Use Search all files (Ctrl/Cmd + Shift + F).
  3. Search for prefixes: sk-, sk_live_, rk_live_, sk-ant-, AKIA, ghp_, xoxb-, SG. and service_role.

Also check whether your JavaScript references source maps (//# sourceMappingURL=). If those maps are public, your original source code, including any hard-coded values, can be reconstructed.

How to fix it

1. Revoke the key first

Assume a leaked key has already been copied. Revoke it in the provider's dashboard and check the usage logs.

2. Keep the new key on the server

Store it in an environment variable without a public prefix, so the bundler never includes it in browser code.

3. Call the provider from a server route

In Next.js, for example, create a route handler that reads the key from process.env and calls the API. The browser calls your route, never the provider. Add authentication and rate limiting to that route, otherwise you have only moved the problem.

4. Re-scan after deploying

Scan again to confirm the key is gone from every bundle, including old cached chunks that might still be served.

Keep it from happening again

  • Add secret scanning to your repository and CI.
  • Turn off production source maps unless you upload them privately to your error tracker.
  • Monitor your live site weekly, because the next AI-generated change can reintroduce the problem.