API key leak checker

Paste JavaScript from your browser, an .env file, a config or a git diff. Every API key in it is named, rated public by design or secret, and given its rotation steps and the code that moves it to your server. The scan runs in this tab.

Runs in your browser. Nothing you paste leaves this page.

Paste, drop or open a file. Minified bundles up to 20 MB.

Results appear here as you paste: each key named, rated public or secret, with the fix.OpenAI, Anthropic, Gemini, Stripe, Clerk, AWS, Supabase, Firebase, GitHub, Slack, Twilio, SendGrid, Resend, database URLs, private keys and more.

Where to find your app's JavaScript

  1. Open your live app and press F12, or Cmd+Option+I on a Mac.
  2. Search every file at once with Ctrl+Shift+F (Cmd+Option+F) for sk-, sk_live, service_role, AIza or secret.
  3. Or open Sources (Debugger in Firefox), then your domain: assets/index-….js for Vite apps (Lovable, Bolt), _next/static/chunks/ for Next.js. Click {} to format, select all, copy, paste above.

Check your live app instead

A paste shows one file. The free check loads your app like a visitor and reads every script it gets: keys, backend, tables named in the code. About ten seconds, no account.

What the API key leak checker looks for

It reads the text you paste and matches it against the formats providers give their keys: OpenAI, Anthropic, Gemini, Groq, Stripe, Clerk, AWS, Supabase, Firebase, GitHub, Slack, Twilio, SendGrid, Resend, Hugging Face and more, plus database URLs with a password, private keys and signing secrets such as JWT_SECRET. For each match it tells you three things: whether the key is meant to be public, where it sits (a browser variable, a bundle, a commit, a server-only env variable), and what to do about it.

RatingExamplesWhat it means
Secretsk-proj- (OpenAI), sk-ant- (Anthropic), sk_live_ (Stripe or Clerk), Supabase service_role and sb_secret_, AWS AKIA with its secret key, ghp_ (GitHub), postgres://user:password@Anyone who reads it can use it, on your bill or with your data. Rotate it.
Public by designSupabase anon and sb_publishable_, the Firebase apiKey, Stripe pk_live_, PostHog phc_, a Sentry DSN, Mapbox pk.Meant for browsers. What protects you is behind it: RLS, Security Rules, key restrictions.
To checkGoogle AIza keys outside a Firebase config, sk- keys of other AI providers, random values under names like SECRET or TOKENCould be either. The row says how to find out.

Why each check matters

  • The variable prefix. NEXT_PUBLIC_, VITE_, REACT_APP_ and EXPO_PUBLIC_ tell the build to copy the value into the JavaScript every visitor downloads. The Next.js docs say the value "will be inlined into any JavaScript sent to the browser", and the Vite docs say VITE_* variables "should not contain sensitive information such as API keys". A secret under one of these names is flagged even when the rest of the file is fine.
  • The Supabase role. The anon key and the service role key look alike: both start with eyJ. The checker decodes the token in your browser and reads its role. The anon key is public; a service role key ignores row level security and opens every table.
  • The context of a Google key. Firebase says its keys "only identify your Firebase project" and may sit in code. But in February 2026 Truffle Security showed that Google keys published for Maps or Firebase can call Gemini once the Generative Language API is on in the same project. The checker reads the code around the key (a Firebase config, a Maps loader, a Gemini client) and rates it from that.
  • Stripe or Clerk. Both use sk_live_ and sk_test_. The names around the key usually tell them apart; when they do not, the result says "Stripe or Clerk" instead of guessing.
  • The browser flag. The OpenAI and Anthropic SDKs refuse to run in a browser unless dangerouslyAllowBrowser is set, because the key they hold would ship to every visitor. Finding it in your code is a strong sign a key is in your bundle.
  • Commits. In a git diff, keys on added lines are marked as committed. Deleting the line later does not remove the key from history.

How to read the result

The verdict comes first, in one sentence. Red means at least one secret sits where a stranger can read it: a browser variable, a bundle, a commit, or hard-coded in code. Amber means secrets only in server-only variables of an env file, which is where they belong as long as the file stays private, or values worth a second look. Green means only public keys, or nothing found.

Each row shows the value redacted to its first 6 and last 4 characters, its line, and the variable it is stored under. Then what a stranger can do with it, the steps in order with a link to the provider's dashboard, and code you can copy. The "Copy a fix prompt" button gives your coding agent the list of findings, still redacted, and the changes to make.

How to fix a key the checker flags

  1. 1

    Create a new key

    In the provider's dashboard, create a replacement and put it in your host's server environment, under a name without a public prefix.

  2. 2

    Revoke the old one

    Until you do, anyone who copied it keeps using it. Rotating without revoking leaves the leak open.

  3. 3

    Read the usage and billing logs

    Look for calls, charges or data reads since the key was first deployed or committed.

  4. 4

    Move the call to your server

    The browser calls your route; your route checks the user and calls the provider with the key.

ts
// app/api/ai/route.ts: runs on the server, the key never reaches the browser
export async function POST(req: Request) {
  // Check the caller is signed in first, or anyone can spend your credits.
  const { prompt } = await req.json();
  const res = await fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ model: "YOUR_MODEL", messages: [{ role: "user", content: prompt }] }),
  });
  return new Response(res.body, { status: res.status });
}
A Next.js route handler. On Lovable or Bolt, the same code goes in a Supabase Edge Function.
bash
# .env.local
# Before: NEXT_PUBLIC_OPENAI_API_KEY=sk-proj-...
OPENAI_API_KEY=your-new-key

# .gitignore
.env*
!.env.example
Then rename the variable so the build stops shipping it, and keep env files out of git.

A route that holds the key still needs a sign-in check and a rate limit, or strangers call your route instead of the provider: see how to protect an AI endpoint. The full incident playbook, provider by provider, is in what to do when an API key leaks.

What a static check cannot tell you

  • Whether a key still works. Nothing is sent to any provider, so a revoked key and a live one look the same. Treat every secret it finds as live until you have revoked it.
  • Keys without a fixed format. Mistral or Algolia admin keys are plain random strings. They are caught by the name they are stored under, with lower confidence, or not at all.
  • The rest of your app. A paste is one file. Your live app loads many scripts, and some keys arrive at run time from an API response. The free check loads the app like a visitor and reads all of them.
  • What a public key opens. The anon key is only harmless if row level security holds. In CVE-2025-48757, 170 of 1,645 Lovable apps tested had missing or weak RLS, about one in ten. Use the Supabase RLS checker or the Firebase rules checker for the rules behind your public keys.

Questions

Is it safe to paste my API keys into this checker?

The scan runs in your browser tab: no request carries what you paste, and analytics only count the verdict, never the text. You can check it yourself by turning off your network before you paste. If a key was ever pasted somewhere you do not trust, rotate it anyway.

How do I find API keys exposed in my frontend JavaScript?

Open your live app, press F12, then Ctrl+Shift+F (Cmd+Option+F on a Mac) to search every loaded script for sk-, sk_live, service_role or AIza. Or copy the main bundle from the Sources tab and paste it here. The free check does the same from your app's address.

Is it OK to have an API key in frontend code?

Only keys built to be public: the Supabase anon or publishable key, the Firebase config key, Stripe pk_ keys, PostHog phc_ keys and restricted Maps keys. Secret keys never belong there, and a NEXT_PUBLIC_ or VITE_ prefix publishes whatever it holds. More in API key exposed in frontend.

What should I do if my API key was leaked?

Create a new key, revoke the old one, then read the provider's usage and billing logs for activity you did not cause. Deleting the commit or the line does not help: anyone who saw the key still has it. Then move the call to a server route so the new key never reaches the browser.

Does this leaked API key checker test whether a key still works?

No. It sends nothing to any provider, so it cannot tell a revoked key from a live one, and it rates every secret as if it works. A full Keybrum attack on your live app looks for leaked secrets in what the app serves and proves each finding with the request that worked.

Why does the checker say my Firebase or Google Maps key is public?

Google designed those keys to sit in web pages: they identify your project, and your Security Rules or key restrictions decide what they can do. Restrict each key to the APIs it needs and to your domains, and keep the Generative Language API off any key that is in a browser.

More free tools

Your app is public. So are its mistakes.

Check what any attacker can already see in it, free, in ten seconds. The full attack, with proof and fixes: €49 once, or €29 a month on a plan.

or continue with Google or GitHub