# API keys in your JavaScript bundle, how they get there and what to do

By Mark Kashef, founder of Lockpick. Published 2026-10-08, updated 2026-10-08.

Why a secret key in your frontend code is readable by anyone, how build tools put it there, which keys are fine to ship, and the order to fix it in.

If a secret key is in your JavaScript bundle, it is public. Your website's code runs in the visitor's browser, so the browser has to download it, and anyone can open it and read it. Replace the key first, then move the code that needs it to your server.

## How does a key end up in the bundle?

Usually through a public prefix. Next.js inlines any `NEXT_PUBLIC_` value into the JavaScript sent to the browser. Vite exposes `VITE_` variables in client-side source code after bundling, and its docs say they should not contain sensitive information such as API keys. A key pasted into a component while testing ends up there too.

## Which keys are fine to ship?

| Key | Fine in the browser? | Why |
| --- | --- | --- |
| Supabase publishable or anon key | Yes | It only reaches what your access rules allow |
| Stripe publishable key | Yes | It can only start a checkout |
| Stripe secret key | No | It can act on your whole account |
| OpenAI or Anthropic API key | No | Anyone can spend your credit with it |
| Supabase secret or `service_role` key | No | It skips row level security |

## What to do, in order

1. Treat a leaked key as used, because even if you remove it now, someone may already have it.
2. Create a new key with the service that issued it and delete the old one.
3. Move the call that needs it into a server route or function that reads the key from an environment variable or your host's secrets.
4. Deploy, then check the live site again so you know the old bundle is gone.

Replacing the key matters more than deleting it from your code, because deleting only stops new copies. Check the service's usage and bills for anything you did not do.

## How to find one

Atlas, our example app at atlas.example, is the kind of site to test. Run a [quick check](/check) on your published address to see what a stranger sees, then read [how we check](/docs/security/how-we-check) for what it covers. An outside check reads the scripts the live site serves. It does not see your repository, so a key that only lives in your code history needs a repository scan as well.

## Questions people ask

### I deleted the key from my code. Am I safe?

Not yet. Anyone who already copied it can still use it, so replace the key with the service that issued it.

### Is hiding the key in an environment variable enough?

Only if the variable has no public prefix and the code that reads it runs on the server. A public prefix puts the value back in the bundle.

## Sources

- [A secret key in your website's code](https://www.lockpick.app/docs/learn/a-secret-key-in-your-code), Lockpick docs, read on 2026-10-06
- [Env Variables and Modes](https://vite.dev/guide/env-and-mode), Vite docs, read on 2026-10-06
- [How to use environment variables in Next.js](https://nextjs.org/docs/app/guides/environment-variables), Next.js docs, read on 2026-10-06
