Skip to content

Is your API key sitting in your website's code? How to check in five minutes

Everything your website sends to the browser is public, including any API key in the JavaScript. AI coding tools sometimes put secret keys there because it makes a feature work quickly. To check, open your live site, press F12, open the Sources or Network tab, and search for strings like sk-, sk_live_, secret and token. If you find a secret key, move the call that uses it to your server, then revoke the key and create a new one, because anyone could have copied it already. GitGuardian counted 28.65 million new secrets leaked on public GitHub in 2025 alone.

By VibeGuard Team4 min read

There's one rule about websites that explains a lot of security incidents: everything your site sends to the browser belongs to whoever is using the browser.

That includes your JavaScript files. They get compressed and renamed during the build, so they look unreadable, but every string inside them is still there. If one of those strings is a secret API key, anyone who opens your site can copy it and use it. On your account, on your bill.

AI coding tools put keys in the frontend more often than you'd hope. It's rarely malicious. When you ask for "a button that summarises this text with GPT", the fastest working answer is to call the AI provider directly from the page, key included. The feature works in the preview, you ship it, and the key ships with it.

Keys that are fine, keys that aren't

Not every key in your frontend is a problem. Some services issue keys designed to be public, and they rely on other protections.

Fine in the browser:

  • A Supabase anon or publishable key, protected by Row Level Security on your tables
  • A Stripe publishable key, starting pk_live_ or pk_test_
  • A Firebase web config (the apiKey there identifies your project and is protected by Firebase Security Rules)
  • A Google Maps key restricted to your own domain

Never fine in the browser:

  • Anything starting sk- (OpenAI and several other AI providers) or sk_live_ (Stripe secret keys)
  • A Supabase service_role or secret key, which ignores every database rule
  • Email provider keys (Resend, SendGrid, Postmark), which let anyone send mail as you
  • Any key whose name includes secret, private, admin or server

When in doubt, check the provider's docs for whether the key is "publishable" or "secret". They almost always say.

How to check your live site in five minutes

Do this on the deployed site, not your code editor. What matters is what actually reached the browser.

  1. Open your site in Chrome and sign in, so the app loads the parts only users see.
  2. Press F12 (or right-click and choose Inspect), then open the Sources tab.
  3. Press Ctrl+Shift+F (Cmd+Option+F on a Mac) to search across every file the page loaded.
  4. Search one at a time for: sk-, sk_live_, service_role, secret, private_key, Bearer, and the names of the paid services you use.
  5. Then open the Network tab, use your app's features, and click through a few requests. Look at the request headers for anything labelled Authorization or x-api-key going to a third party (like api.openai.com) directly from the browser.

If a request goes from the browser straight to an AI or email provider with a key attached, that key is public, even if it never appears as readable text in the source.

The environment variable trap

A common response is "but I put it in an environment variable". Environment variables protect secrets only when they're read on a server.

Modern frameworks copy some variables into the browser code on purpose, so the frontend can use things like your public Supabase URL. Which ones depends on a prefix. In Next.js, anything starting NEXT_PUBLIC_ is written into the JavaScript at build time. In Vite, which Lovable and Bolt use, it's anything starting VITE_. Vite's own documentation warns that these variables should not contain sensitive information for exactly this reason.

So NEXT_PUBLIC_OPENAI_KEY or VITE_STRIPE_SECRET is a secret published to every visitor, just with extra steps.

If you find one

Do these in order.

First, move the call to the server. Ask your AI tool for a server route (or a Supabase Edge Function) that holds the key and makes the call, and have the page call your route instead. Ask for that route to require a signed-in user and to limit how often each user can call it, otherwise you've moved the problem rather than fixed it.

Second, revoke the old key and create a new one. This is the step people skip. Moving the key doesn't un-publish it. Anyone who visited your site while it was exposed may have a copy, and so may any bot that scrapes sites for keys. The Moltbook exposure started with a key found in exactly this kind of JavaScript file.

Third, check the provider's usage dashboard for activity you don't recognise, and set a spending limit if the provider offers one.

Why this keeps happening at scale

GitGuardian, which scans public code for leaked credentials, counted 28.65 million new hardcoded secrets pushed to public GitHub in 2025, up 34% on the year before. Secrets for AI services alone rose 81%. Their report also found that 64% of valid secrets leaked in 2022 were still usable in January 2026, because nobody revoked them.

That's the pattern to break. Finding a key is uncomfortable. Finding it and not revoking it is how an embarrassing week turns into a bill. Our pre-launch checklist covers the rest of the secrets section, including keys you pasted into an AI chat.

Questions founders ask

Which keys are safe to have in the browser?

Keys designed to be public: a Supabase anon or publishable key (protected by Row Level Security), a Stripe publishable key starting pk_, a Firebase web config, or a Google Maps key restricted to your domain. Anything described as secret, private, server or service role is not.

I put the key in an environment variable. Isn't that enough?

Only if the variable is used on the server. Frameworks like Next.js and Vite deliberately copy variables with a public prefix, such as NEXT_PUBLIC_ or VITE_, into the browser code at build time. A secret in one of those is shipped to every visitor.

How do I move an API call to the server if I don't code?

Ask your AI tool something specific: 'Move the call to the OpenAI API out of the frontend into a server route. The key must only be read on the server. The route must require a signed-in user and limit each user to N requests per minute.' Then search the built site again to confirm the key is gone.

Sources

  1. The State of Secrets Sprawl 2026 · GitGuardian, 17 Mar 2026
  2. Environment Variables · Next.js Docs
  3. Env Variables and Modes · Vite Docs
  4. Hacking Moltbook: AI Social Network Reveals 1.5M API Keys · Wiz Research, 2 Feb 2026

Is your app one of them?

An independent security check of your live app, from €59, with fix prompts for the coding tool you already use. Read-only, and it never touches your code.

Check my app

Keep reading

All articles