← Learn

Definition

Why isn't an environment variable enough to hide a secret?

We scanned nearly 2,000 AI-built apps and 1 in 8 shipped a high-severity flaw. Want to check yours?Scan free β†’

An environment variable keeps a secret out of your source code and git history, but it does not make the secret private if the code that reads it runs in the browser. Anything used in client-side code, including any value a framework marks as public, is bundled and shipped to every visitor. A secret is only hidden if it is read and used on the server.

What env vars actually do

They move the value out of committed source. That solves the git-history leak, which is real and worth solving, but it is only half the problem. Where the value is used matters as much as where it is stored.

The browser is public

In Next.js, a NEXT_PUBLIC_ prefix inlines the value into the client bundle. In Vite, import.meta.env values used in components ship too. Any secret referenced in client code can be read from the browser, no matter how you stored it. Secret keys must be used only in server code.

Does the secret actually stay private?

Where the value is readExposed to the browser?
Server component, route handler, or server actionNo, it stays on the server
Client component with a NEXT_PUBLIC_ prefixYes, inlined into the bundle
Client component using Vite import.meta.env in the UIYes, shipped to every visitor
Env var that is set but only read in server codeNo, safe

What this means for AI-generated code

AI assistants often fix a client-side undefined-variable error by adding a public prefix, which quietly ships the secret to the browser. The code works, so the leak is invisible until someone reads the bundle. Keep secret keys in server components, route handlers, or server actions only.

Common questions

If I put a secret in an environment variable, is it safe?

Only if the code that reads it runs on the server. An environment variable keeps the value out of your source and git history, but if a client component reads it, the value is bundled and shipped to the browser where anyone can read it.

What does the NEXT_PUBLIC_ prefix do?

It tells Next.js to inline that environment variable into the client-side JavaScript bundle so browser code can use it. That makes it public. Only put values on it that are safe for everyone to see, never a secret or service_role key.

How can I tell if a secret shipped to the browser?

Open your deployed app, view the page source or the network tab, and search the JavaScript for the value or its prefix (like sk_ or eyJ). If you can find it in the browser, so can anyone else. A scanner like Prbl checks this for you.

Where should a secret key be used in a Next.js app?

In server-only code: server components, route handlers under app/api, or server actions. These run on the server and never send their variables to the browser, so a secret read there stays private.

Want to know if your app has this issue? Scan your live app or a public repo free, no account needed.

Scan my app β†’

Related: how this happens in v0 / Next.js

Client-Side vs Server-Side Secrets: Why env Vars Aren't Enough: Prbl