Skip to content
✕PreflightX Scan your app — free
  1. PreflightX
  2. Guides
  3. Exposed API keys in JavaScript: safe to ship or rotate now?

PREFLIGHTX / SECURITY GUIDES

Exposed API keys in JavaScript: safe to ship or rotate now?

Which API keys are safe in frontend code and which leak money or data, how to find what your app ships, and what to do when a secret is out.

Published September 27, 2026 · Updated September 27, 2026 · By the PreflightX team

On this page
  1. Keys that are designed to be public
  2. Keys that must never be in frontend code
  3. How secrets end up in the bundle
  4. How to check what your app ships
  5. If a secret key is exposed: do this in order
  6. Frequently asked questions

Check your live app in about a minute. Read-only, no signup, every finding free.

Scan my app — free

Everything your frontend needs to run is downloaded by every visitor. That includes any key your code uses directly. Escape's October 2025 study of 5,600+ public vibe-coded apps found 400+ exposed secrets, and VibeEval's August 2026 scan found that 1,332 of 30,998 live apps shipped a secret, roughly 1 in 23.

Not every key in a bundle is a problem, though. The question is which kind of key it is.

Short answer: publishable keys (Supabase anon, Firebase web config, Stripe pk_) are designed to be public and are protected by rules on the provider's side. Secret keys (Stripe sk_, OpenAI, Anthropic, Supabase service role, database URLs with a password) must never reach the browser. If one did, rotate it first and ask questions later.

Keys that are designed to be public

These identify your project. They are safe in the browser as long as the rules behind them are right:

Key Looks like What actually protects you
Supabase public key sb_publishable_… or an anon JWT Row Level Security and your policies
Firebase web config apiKey: "AIza…" inside firebaseConfig Firebase Security Rules for Firestore, Realtime Database and Storage
Stripe publishable key pk_live_… / pk_test_… Stripe only lets it create tokens and start checkout
Mapbox public token pk.… URL restrictions on the token
Algolia search key search-only API key Read-only by design; never ship the admin key
Google Maps browser key AIza… HTTP referrer and API restrictions in Google Cloud

A public key with bad rules behind it is still a leak. It is the rules, not the key, that need fixing.

Keys that must never be in frontend code

Key Looks like What someone can do with it
Stripe secret or restricted key sk_live_…, rk_live_… Read customers, issue refunds, create charges
OpenAI key sk-proj-…, sk-… Run up your bill on your account
Anthropic key sk-ant-… Same: usage billed to you
Supabase secret / service role sb_secret_… or a service_role JWT Bypass every RLS policy: read and change all data
Database connection string postgres://user:password@… Connect to your database directly
GitHub token ghp_…, github_pat_… Read or push to your repositories
Email and SMS providers SendGrid SG.…, Twilio auth token, Mailgun Send spam or phishing from your domain
Signing secrets JWT_SECRET, NEXTAUTH_SECRET Forge sessions and log in as anyone

How secrets end up in the bundle

The most common route is an environment variable with a public prefix. Build tools inline these into the JavaScript on purpose:

  • Vite: anything starting with VITE_
  • Next.js: anything starting with NEXT_PUBLIC_
  • Create React App: anything starting with REACT_APP_
  • Expo: anything starting with EXPO_PUBLIC_

VITE_OPENAI_API_KEY is not hidden because it came from a .env file. It is compiled into your site. The prefix is exactly the instruction "put this in the browser".

The second route is an AI assistant calling a paid API directly from a React component, because that is the shortest path to a working demo. It works, and every visitor can copy the key from the network tab.

How to check what your app ships

  1. Open your live site, then your browser's developer tools.
  2. In Sources (Chrome) or Debugger (Firefox), search across all files (Ctrl/Cmd + Shift + F) for sk_, sk-, service_role, sb_secret, postgres://, SECRET and KEY.
  3. In the Network tab, watch the requests your app makes. A request that goes straight from the browser to api.openai.com or api.stripe.com with a secret in its headers is the problem, visible to anyone.
  4. Locally, search your production build output (dist/, .next/, build/) for the same strings.

Or run a PreflightX scan: it fetches your HTML and JavaScript bundles like a visitor would and reports each credential with its type, file and line, showing only the last four characters.

If a secret key is exposed: do this in order

  1. Rotate it now. Create a new key in the provider's dashboard and revoke the old one. Deleting it from your code is not enough: old bundles stay cached, and your git history still has it.
  2. Check what it was used for. Look at the provider's usage, logs and billing since the key went live. Set a spending limit where the provider offers one.
  3. Move the call to the server. Put the secret in a server-only environment variable (no public prefix) and call the provider from a backend route, a Supabase Edge Function, or a serverless function. The browser talks to your function; only your function knows the key.
  4. Add authorization to that function. A server route that anyone can call with any input is just a slower way to leak your key's budget. Require a signed-in user and validate what they send.
  5. Scan again after you deploy, and confirm the key is gone from the live bundle.

Frequently asked questions

Is it safe to put my Firebase API key in the frontend? Yes. The Firebase web apiKey identifies your project. What protects your data is Firebase Security Rules, so check those instead.

My key is only in a .env file. Is that enough? Only if it has no public prefix and is used exclusively by server-side code. A VITE_ or NEXT_PUBLIC_ variable ends up in the browser no matter which file it came from.

The key was only exposed for a few hours. Do I still need to rotate it? Yes. Bots scan public sites and repositories for keys continuously. Treat any exposed secret as compromised.

Check what your app exposes right now

PreflightX runs a read-only scan of your live app's public surface: exposed keys in your JavaScript, readable Supabase tables, open storage buckets, deployed .env and .git files, source maps and missing security headers. Every finding is free to see.

Scan my app — free

More security guides

  • Vibe coding security statistics 2026: what scans found
  • Is your Supabase database public? Check Row Level Security
  • Security headers for AI-built apps: CSP, HSTS and CORS
  • .env and .git exposed on your site? How to check and fix
  • Security checklist for Lovable, Bolt, Cursor and v0 apps
✕PreflightX

A safer internet starts with you.

GuidesPrivacyTermsRefundsAcceptable UseCookiesContact
© 2026 PreflightX