DEV Community

SniffPup
SniffPup

Posted on Originally published at sniffpup.com

How to find exposed API keys on your website (a 7-step check)

Disclosure: we build SniffPup, a free passive scanner for live sites. This guide was first published on our site, and every step works without it.

Short answer: anything your site sends to the browser (HTML, JavaScript bundles, source maps, files left in the web root) can be read by every visitor. To find leaked keys, look at your published site the way a stranger would.

1. Know which keys are allowed to be public

Some keys are made for the browser: Supabase anon or sb_publishable_ keys, Stripe pk_live_ keys and Firebase web config. Finding them is normal.

Secret keys are different. If any of these shows up in your frontend, treat it as leaked:

  • Supabase service_role or sb_secret_ (they bypass Row Level Security)
  • Stripe sk_live_ and whsec_
  • OpenAI sk- and Anthropic sk-ant-
  • AWS AKIA… with its secret
  • GitHub ghp_
  • database URLs with a password

2. Search your JavaScript bundles in the browser

Open your published site (not the editor preview), open DevTools, then Sources. Press Ctrl+Shift+F (Cmd+Option+F on Mac) to search across all loaded files, and try:

sk-, sk-ant-, sk_live_, rk_live_, whsec_
service_role, sb_secret_
AKIA, ghp_, github_pat_, xox, SG., gsk_, xai-
PRIVATE KEY, postgres://, mongodb+srv://
Enter fullscreen mode Exit fullscreen mode

Minifying doesn't hide a key: it stays a plain string. Also click around the app with the Network tab open and look at request headers. An Authorization: Bearer sk-… header going from the browser straight to OpenAI or Stripe means the key is in your frontend.

3. Check your build output locally

If you have the code, build it and search the output:

grep -rnE "sk_live_|sk-|service_role|sb_secret_" dist/ .next/static/ build/
Enter fullscreen mode Exit fullscreen mode

Any environment variable with a VITE_, NEXT_PUBLIC_ or EXPO_PUBLIC_ prefix is copied into the browser bundle by design, so never put a secret in one.

4. Try the files that shouldn't be public

Visit these on your live domain: /.env, /.env.local, /.env.production, /.git/config, /.git/HEAD and /.npmrc.

  • A 404 is good.
  • Lines like KEY=value or a [core] section mean the file is public.

Watch out: many single-page apps return your home page for every unknown URL. That looks like a 200 but is harmless. What matters is whether the real file contents come back.

5. Check for public source maps

Open one of your .js files and add .map to the URL. If it downloads, anyone can read your original, unminified source, including comments and any values that were inlined at build time. Turn off production source maps or keep them private.

6. Check your git history too

A key you deleted can still live in old commits. Run a tool such as gitleaks or TruffleHog on your repo. An outside scanner (ours included) can't see your repo.

7. If you find a secret key: rotate, then move it server-side

  1. Revoke and reissue the key at the provider right away. Deleting it from your code is not enough.
  2. Check the provider's usage or billing page for calls you didn't make.
  3. Move the call into server-side code (a Supabase Edge Function, an API route or a serverless function) that reads the key from a secret store and checks who is calling.
  4. Delete any .env or .git files from the deployed web root and redeploy.
  5. Re-check to confirm the leak is gone.

If you'd rather automate it

A free SniffPup scan of your live URL runs these outside checks: secrets in your HTML and same-origin JS (always masked), public .env/.git files (variable names only, never values), downloadable source maps, security headers and more. It's passive: about 60 requests or fewer, no logins, and it never uses a secret key it finds. It can't see your repo, your server code or anything behind a login, and it doesn't scan native mobile apps. A clean report is not a guarantee of security.

FAQ

Is it safe to have my Supabase anon key or Stripe publishable key in my frontend?
Yes, those keys are designed to be public. But a Supabase anon or sb_publishable_ key is only safe if Row Level Security is on for every exposed table.

I deleted the key from my code. Am I safe now?
No. If a secret key was ever public, assume someone copied it. Revoke and reissue it at the provider. Removing it from the code only stops new leaks.

Does SniffPup use the keys it finds?
No. It masks any secret in the report and never uses a secret key it finds. The only key it sends anywhere is the public Supabase anon key your site already ships to every visitor. It uses that for a read-only check (one HEAD request per table, up to 8) that shows whether a signed-out visitor can read at least one row, without downloading any rows.

Feedback shapes what we build next. If there's a check you want, tell us: https://sniffpup.com/suggest

Top comments (0)