Some of them are, by design. Any setting your frontend reads is bundled into the JavaScript every visitor downloads. In Vite apps that's every variable starting VITE_; in Next.js, every one starting NEXT_PUBLIC_. That's fine for things meant to be public, such as your site's address or a publishable key. It's a leak for anything secret. Separately, check that your .env file itself can't be downloaded from your site.
What's the problem
You were told to keep keys out of the code and put them in environment variables, so you did. But the app still works in the browser with those keys, which means the browser has them. And anything the browser has, anyone can read.
Why it happens
- "Environment variable" doesn't mean secret. On a server, environment variables stay on the server. In a frontend build, the build tool copies the values into the code it produces, so they ship to every visitor.
- The prefixes are the switch. Vite only exposes variables starting
VITE_, and Next.js only those startingNEXT_PUBLIC_. Developers often add the prefix to make an error go away, and with it publish the secret. - The
.envfile is in the wrong place. If it sits in the folder your web server serves, anyone can requestyoursite.com/.envand download it.
How to fix it
- List every variable your frontend uses. Search the code for
import.meta.env.VITE_andprocess.env.NEXT_PUBLIC_, or your framework's equivalent. - Sort them into public and secret. Public: site addresses, publishable keys designed for browsers, analytics IDs. Secret: anything that grants access, spends money, or bypasses security, such as service keys, database passwords and AI or payment API keys.
- Move every secret behind your server. The browser calls your backend or a serverless function, which holds the key and makes the call.
- Rotate every secret that was ever exposed. Removing it from the code isn't enough. Someone may already have it.
- Check
yoursite.com/.envreturns "not found", and that.envis listed in.gitignoreso it never reaches the repository.
When to call Preventionlabs
If two or three variables need moving and you have a backend, that's an afternoon. Call us when there's no server side to move them to, when secrets run through the whole frontend, or when you're not sure what's exposed. Data exposure is on the MVP-level protection checklist in every resurrection, and it's checked the way an attacker would check it: by reading what your site sends to the browser.
Submit your project for a free assessmentFree assessment. $10,000 AUD flat to get it live, only if we take it on and you go ahead.
Sources
- Vite: Env Variables and Modes: Protecting secretsbuild tool docs
VITE_* variables should not contain sensitive information such as API keys.
- Vite: Env Variables and Modesbuild tool docs
The values of these variables are bundled into your source code at build time.
- Next.js: Environment Variablesframework docs
It will be inlined into any JavaScript sent to the browser.
- Next.js: Environment Variablesframework docs
Non- NEXT_PUBLIC_ environment variables are only available in the Node.js environment, meaning they aren't accessible to the browser
- Supabase: API keysplatform docs
Never put one in a browser, a shipped application, or source control.