$ grep -r "sk_live_" ./

Are My API Keys or Secrets Exposed? How to Check

Leaked keys are one of the most common and most expensive mistakes in AI-built apps. Here is how to tell if yours are sitting in public, and what to do today if they are.

saasreview·June 14, 2026·12 min read

To check if your API keys are exposed, open your live app, press F12 to open the browser dev tools, and search the loaded JavaScript and the Network tab for words like key, secret, token, or prefixes like sk_. If you can see a secret value sitting there, so can anyone else. The fix starts with rotating that key today.

What is an API key, and why does it matter if one leaks?

An API key is a password your app uses to talk to another service: Stripe to charge cards, OpenAI to call a model, a database to read and write your users' data, an email provider to send mail. There are two kinds, and the difference is the whole game. A publishable (or public) key is designed to live in the browser and do harmless things. A secret key is the one that can move money, read private records, or run up a bill. A leaked secret key is not a theoretical risk. It is a stranger with your wallet and your customer list.

Here is the part that stings: most leaks do not get noticed by you. They get noticed by someone running an automated scanner across public code, or by a bot watching for new keys to appear. By the time you see a surprise charge or a weird login, the damage is already done. That is the quiet cost of a leak. It is happening while you read this, not at some future date when you finally get around to a security pass.

How do AI coding tools end up putting secrets in the browser or a public repo?

AI coding tools optimize for one thing: getting your feature to work, fast. When you ask Cursor, Claude, Lovable, v0, or Bolt to "connect Stripe" or "add OpenAI," the quickest path that runs on the first try is often to drop the key straight into the frontend code or hardcode it inline. It works in the demo, you move on, and the secret is now baked into something the browser downloads. This is a known pattern in apps built fast with AI, and it is nobody's character flaw. It is just what "make it work" produces when nobody asked "is this safe to ship."

The two most common ways a secret ends up public:

  • In the frontend bundle. The key is in code that ships to the browser (a React component, a config.js, a Vite env var prefixed VITE_ or NEXT_PUBLIC_). Anyone can read it by viewing source or opening the Network tab. It is not hidden by being minified.
  • In a committed `.env` file. Your secrets file got pushed to GitHub. If the repo is public, the key is searchable. Even if you delete the file later, git keeps it in history, so it is still there for anyone who looks.

!Anything in the browser is public, full stop

There is no such thing as a "hidden" value in frontend code. Minifying, obfuscating, or putting it in an environment variable that ships to the browser does not protect it. If the browser needs it to run, a person can read it. Secret keys must stay on a server the browser cannot see into.

How can I check right now whether my keys are visible to a stranger?

You can do a solid first-pass check in about ten minutes, for free, with tools you already have. The goal is to look at your app the way a curious stranger would, not the way you remember building it. Run through these in order.

1. Search your live site in the browser

  1. 1.Open your live app in Chrome or Firefox. Press F12 (or right-click and choose Inspect) to open dev tools.
  2. 2.Go to the Sources tab. Press Ctrl+Shift+F (Cmd+Option+F on Mac) to search across all loaded files. Search for: secret, sk_, token, api_key, apikey, password, Bearer.
  3. 3.Click around your app: sign in, load a page, submit a form. Then open the Network tab and look at the requests. Click a few and read the Headers and Response. A secret key sitting in a response body or a request your browser is making is a red flag.

What you want to see: only publishable keys (Stripe keys starting pk_, a public Supabase anon key, a public Mapbox token). What you do not want to see: anything starting sk_, a database connection string, an admin token, or a private key for OpenAI, SendGrid, AWS, and the like.

2. Search your code and your git history

In your project folder, search the code for the same words. If you have a terminal, this catches secrets even before they reach the browser:

$bash
# look for common secret prefixes and words in your code
grep -rEn "sk_live_|sk_test_|api[_-]?key|secret|BEGIN PRIVATE KEY" . \
  --exclude-dir=node_modules --exclude-dir=.git

# did your .env ever get committed? this should print NOTHING
git log --all --full-history -- "*.env" ".env*"

If that second command prints any commits, your .env is in git history and must be treated as leaked, even if the repo is private. Private repos get cloned, shared, and made public by accident more than anyone admits.

3. Check GitHub directly

If your code is on GitHub, open your repo and confirm there is no .env, config.json with real values, or credentials file sitting in the file list. GitHub also runs secret scanning and emails you if it spots a known key format in a public repo. If you have ever gotten one of those alerts and clicked past it, go back and read it. That email is GitHub telling you a real key is real and public.

What is the difference between a publishable key and a secret key?

A publishable key is built to be seen. Stripe's pk_ key, a Supabase anon key, and most map and analytics tokens are meant to ride along in the browser and are restricted on the server side to only do safe things. Finding one of these in your frontend is normal and fine. A secret key is built to be hidden: Stripe's sk_, your database password, an OpenAI key, an email-provider key, any "service role" or "admin" key. These let the holder act as you. The simple rule: if the service's own docs call it secret, server-side, or warn you to never expose it, it must never touch the browser or git.

//A quick gut check

Ask yourself: "If a competitor or a bored teenager had this exact string, could they spend my money, email my users, or read private data?" If yes, it is a secret and it does not belong anywhere a stranger can reach.

What do I do in the first hour if I find a key exposed?

Move fast, in this order. The instinct is to delete the file and hope, but a leaked key is leaked forever until you replace it. Deleting the code does not un-leak the value. Rotating it does.

  1. 1.Rotate the key first. In the service's dashboard (Stripe, OpenAI, your database host), create a new key or "roll" the existing one. Do this before anything else. For Stripe, the dashboard has a "Roll key" option that issues a new secret and lets you expire the old one.
  2. 2.Put the new key where it belongs. Add it as a server-side environment variable in your host (Vercel, Netlify, Railway, Render, Fly). Not in the code. Not in a frontend env var.
  3. 3.Redeploy so your live app uses the new key. Test that the feature still works.
  4. 4.Revoke the old key. Once the new one is live and working, expire or delete the old key so the leaked one is dead.
  5. 5.Check for damage. Look at recent activity in the service: unexpected charges, API usage you did not cause, logins you do not recognize. If it is a payment key, watch for refunds and disputes over the next few days.

+Rotate before you scrub git history

Cleaning a secret out of git history is fiddly and easy to get wrong. Do not let it block you. Rotate and revoke the key first so the leaked value is worthless. Then, if you want, clean the history at your own pace. A dead key in old commits cannot hurt you.

How do I keep secrets out of the frontend and out of git going forward?

Three habits cover most of it, and none of them require you to become a security engineer.

  • Keep secrets server-side. Calls that use a secret key (charging a card, calling OpenAI, writing to your database with admin rights) should happen in an API route, serverless function, or backend, never in browser code. The browser asks your server, and your server holds the secret.
  • Use environment variables the right way. Store secrets in your host's environment settings. Remember the prefix trap: anything starting VITE_, NEXT_PUBLIC_, REACT_APP_, or PUBLIC_ is shipped to the browser by design. Never put a secret behind one of those.
  • Add `.env` to `.gitignore` before your first commit. This one line stops the most common leak entirely. If you already committed one, see the rotate-then-clean steps above.

This same care matters most where money is involved. Before you turn on payments, it is worth confirming the whole flow is sound, not just the keys. We wrote a companion piece on whether your app is safe to charge money for yet, and another on whether AI set up your login and auth correctly, since a leaked admin token and a broken login often live in the same app.

When should I have someone check from the outside instead of trusting my own look?

Do your own ten-minute check first. It is free and it catches the obvious cases. But here is the honest limit: you cannot fully see your own app the way a stranger does. You know which pages you visit, so you only inspect those. You know the demo path, so you never wander off it. The key you are sure is fine is often the one you stopped looking at months ago. That blind spot is exactly why secrets sit exposed in plain sight for a long time before anyone notices.

If you are about to charge real customers, handle real personal data, or you simply want a second set of eyes, an outside check is worth it. saasreview's Bughunt does exactly this from the outside: it looks at your live app the way a nosy stranger would and hands you a private, plain-English list of what it found. It is an automated passive check, not a human red-team, and we are upfront about that. The result is private and never published. For five minutes of your attention, you find out whether the thing you are quietly worried about is real, before a stranger finds it first.

You did the free check and you want to be sure. Have us look at your live app from the outside and send you a private list of what a stranger could find.

Run a Bughunt on my app
// faq

Frequently asked questions

How do I check if my API key is public?

Open your live app, press F12 to open dev tools, then use the Sources tab to search all loaded files for secret, sk_, token, and api_key. Also check the Network tab for keys in requests or responses. In your code, run a grep for the same words and check that your .env was never committed to git.

My secret key is showing in the browser Network tab. Is that bad?

Yes, if it is a secret key (something like sk_, a database string, or an admin token). Anything in the Network tab is visible to anyone using your app. A publishable key (pk_, a public anon key) is fine there by design. If it is a secret, rotate it now, move it server-side, redeploy, then revoke the old one.

I committed my .env to GitHub. What do I do?

Treat every secret in that file as leaked, even if the repo is private. Rotate each key in its service dashboard, add the new values as server-side environment variables, redeploy, and revoke the old keys. Add .env to .gitignore. Cleaning git history is optional once the keys are dead, since a revoked key in old commits is harmless.

Are environment variables safe to use in the frontend?

Only public ones. Build tools ship any variable prefixed VITE_, NEXT_PUBLIC_, REACT_APP_, or PUBLIC_ straight to the browser, so those must never hold secrets. A secret key belongs in a server-side environment variable that the browser never receives, used only by your backend or API routes.

How do I rotate a leaked Stripe key?

In the Stripe Dashboard, go to Developers, then API keys, and use the roll option on your secret key. Stripe issues a new key and lets you set an expiry on the old one. Put the new key in your host's server-side environment variables, redeploy, confirm payments work, then expire the old key.

Find the exposed key before a stranger does

Our Bughunt looks at your live app from the outside and hands you a private, plain-English list of what it found. Automated, honest, never published.

Run a Bughunt on my app
$ ls related/

Keep reading

We put every SaaS through the same honest scorecard, then publish the result.

Published on saasreview.ai · last updated June 14, 2026