Free tool · Next.js · Vite · Expo

Paste your .env.
See what leaks.

AI agents love to “fix” a missing env var by adding NEXT_PUBLIC_. That ships your Stripe or OpenAI secret to every visitor. This finds it in a second, before you deploy.

env-leak-checker — runs in your browser, nothing is sent or stored

try:

› Checks Next.js, Vite, Expo, Nuxt, SvelteKit, Astro, CRA and Gatsby public prefixes. Values are masked in the results.

next: skip the next one

Skip the cleanup. The VibeBoot SaaS Starter ships with this already handled: only the app URL and app name are NEXT_PUBLIC_, every Stripe, auth and database secret stays server-side, and AGENTS.md and CLAUDE.md tell your agent to keep it that way. Plus auth, Stripe and a database on Next.js 16.4.3. $49, one-time.

14-day money-back guarantee · lifetime updates

  • 17 secret key formats
  • 7 framework prefixes
  • nothing leaves your browser
  • updated

01How a key ends up public

One prefix. Four steps. Zero warnings.

  1. 01The agent hits an errorA client component reads process.env.STRIPE_SECRET_KEY and gets undefined, because only prefixed vars reach the browser.
  2. 02It “fixes” itThe quickest change that makes the error go away: rename the variable to NEXT_PUBLIC_STRIPE_SECRET_KEY. It works.
  3. 03The build inlines itAt build time Next.js replaces process.env.NEXT_PUBLIC_… with the literal value inside your JavaScript files.
  4. 04Anyone can read itOpen DevTools, search the JS for sk_ and copy the key. Bots scan public sites and repos for exactly this.
double-check the real build: list client files that contain secret-looking strings
npm run build && grep -rlE "sk_(live|test)_|rk_(live|test)_|whsec_|sk-(proj|ant)-|service_role|postgres(ql)?://[^\"]+:[^\"]+@" .next/static

No output means none of those patterns are in the files Next.js sends to browsers. Vite builds go to dist/assets instead.

02What can be public

Some keys are built for the browser. Most aren't.

✓ fine with a public prefix

Stripe publishable keypk_live_ / pk_test_
Supabase URL + anon or publishable keyprotected by Row Level Security
Clerk publishable keypk_live_ / pk_test_
PostHog project key, Sentry DSNwrite-only ingest keys
Firebase web configlock it down with security rules
Your app URL, name, analytics IDsnot secrets at all

✕ never with a public prefix

Stripe secret / restricted keysk_ / rk_
Stripe webhook secretwhsec_
OpenAI, Anthropic, xAI, Groq keysanyone can run up your bill
Supabase service_role / secret keyskips Row Level Security
DATABASE_URL, SMTP / Redis URLscontain a password
AUTH_SECRET, GitHub client secretlets people forge sessions
prompt: have your agent audit the whole repo

Audit this project for secrets exposed to the browser. List every env var with a public prefix (NEXT_PUBLIC_, VITE_, EXPO_PUBLIC_, PUBLIC_) and flag any that hold a secret: secret API keys, webhook secrets, service_role keys, database URLs, auth secrets. For each one: rename it without the prefix, read it only in server code (route handlers, server actions, server components) with import "server-only" in that module, and move any client usage behind a server route. Don't add a public prefix to fix an undefined env var. Tell me which keys I need to rotate.

03Start with secrets in the right place

A Next.js SaaS starter your agent can't talk into leaking keys.

Skip the cleanup. The VibeBoot SaaS Starter ships with this already handled: only the app URL and app name are NEXT_PUBLIC_, every Stripe, auth and database secret stays server-side, and AGENTS.md and CLAUDE.md tell your agent to keep it that way. Plus auth, Stripe and a database on Next.js 16.4.3. $49, one-time.

14-day money-back guarantee · lifetime updates

See everything that's inside →
  • 2 public vars · only the app URL and app name use NEXT_PUBLIC_
  • Secrets stay server-side · Stripe, webhook, auth and database secrets have no public prefix in .env.example
  • Agent rules · AGENTS.md, CLAUDE.md and .cursor/rules say: read secrets only on the server
  • Hosted checkout · Stripe Checkout runs from a server route, so the browser needs no Stripe key

FAQ

Is it safe to paste my real .env here?

The checker is plain JavaScript in this page: nothing you paste is sent, logged or stored, and values are masked in the results. You can also paste only the variable names, or replace values with placeholders; name-based checks still work.

Are NEXT_PUBLIC_ variables secret if I only use them on the server?

No. Next.js inlines a NEXT_PUBLIC_ value into the client bundle wherever client code references it. Treat anything with the prefix as public, and keep secrets unprefixed so they stay on the server.

I already deployed a leaked key. Is renaming it enough?

No. Old builds and caches may still serve the JavaScript that contains it, and someone may already have copied it. Rotate (roll) the key with the provider first, then fix the name and redeploy.

Why do AI coding agents do this?

When a client component can't read a server-only variable, adding the public prefix is the shortest change that makes the error disappear. The real fix is moving the call to the server. A rule in AGENTS.md or .cursor/rules that says “never add NEXT_PUBLIC_ to a secret” stops most of it.

Does this work for Vite, Expo, SvelteKit and Astro?

Yes. It checks these public prefixes: NEXT_PUBLIC_ (Next.js), VITE_ (Vite), EXPO_PUBLIC_ (Expo), NUXT_PUBLIC_ (Nuxt), REACT_APP_ (Create React App), GATSBY_ (Gatsby), PUBLIC_ (SvelteKit / Astro).

Sources: Next.js docs on environment variables and data security, Vite's env and modes, Supabase's API keys guide and Stripe's API keys docs. Checked October 23, 2026. Spotted a mistake? Email [email protected].

$ fixed it? get the next one first

New fixes for what AI agents break, by email.

When we add a fix or a Cursor rule for a new Next.js, Auth.js, Prisma or Stripe break, it goes out in the VibeBoot newsletter. Free, occasional, unsubscribe in one click.

Subscribe free

> More free tools

All tools →