Skip to main content
Security Guides

The .env File Trap: Why Your Next.js Secrets Keep Ending Up in the Browser

SecuriSky TeamApril 12, 20268 min read

Introduction to the .env File Trap

When building Next.js applications with tools like Cursor, Lovable, Bolt, v0, or Replit, it's common to store sensitive information such as API keys, database credentials, or other secrets in .env files. However, these secrets often end up in the browser, exposing them to potential attackers. The main reason for this exposure is that Next.js, by default, includes .env files in the client-side bundle, making their contents accessible to anyone using the browser's developer tools.

To understand why this happens, let's look at how Next.js handles environment variables. When you create a .env file in the root of your project, Next.js automatically loads its contents into the process.env object. This object is then available throughout your application, including on the client-side. The problem arises when you use process.env directly in your React components, as this can cause the sensitive information to be bundled with your client-side code.

How Next.js Environment Variables Work

Next.js provides a built-in way to handle environment variables using the env object in next.config.js. You can configure which environment variables are exposed to the client-side by using the env property in your next.config.js file. For example:

// next.config.js

module.exports = {

env: { CUSTOM_ENV_VARIABLE: process.env.CUSTOM_ENV_VARIABLE, },

}

In this example, only the CUSTOM_ENV_VARIABLE environment variable is exposed to the client-side.

The Dangers of Exposed Secrets

Exposed secrets can lead to serious security issues, including unauthorized access to your API, database, or other sensitive resources. For instance, if your .env file contains a Stripe API key, an attacker could use it to make unauthorized charges or access sensitive customer information.

To demonstrate the risk, let's consider an example where we store a Stripe API key in a .env file:

.env

STRIPE_API_KEY=sk_test_1234567890

Then, in our Next.js component, we use this API key to make a request to the Stripe API:

// pages/index.js

import axios from 'axios';

function HomePage() {

const stripeApiKey = process.env.STRIPE_API_KEY; const handlePayment = async () => { try { const response = await axios.post('https://api.stripe.com/v1/payments', { // ... }, { headers: { 'Authorization': Bearer ${stripeApiKey}, }, }); // ... } catch (error) { // ... } }; return ( // ... );

}

In this example, the STRIPE_API_KEY is exposed to the client-side, making it accessible to anyone using the browser's developer tools.

Securing Your Secrets

To secure your secrets, you should avoid storing them in .env files or exposing them to the client-side. Instead, consider using a secrets management service or a secure storage solution like HashiCorp's Vault. You can also use environment variables specific to your serverless functions or API routes, ensuring that sensitive information is only accessible on the server-side.

For example, you can use Next.js API routes to handle sensitive operations, such as payment processing, without exposing your secrets to the client-side:

// pages/api/payment.js

import axios from 'axios';

export default async function handler(req, res) {

const stripeApiKey = process.env.STRIPE_API_KEY; try { const response = await axios.post('https://api.stripe.com/v1/payments', { // ... }, { headers: { 'Authorization': Bearer ${stripeApiKey}, }, }); // ... } catch (error) { // ... }

}

In this example, the STRIPE_API_KEY is only accessible on the server-side, reducing the risk of exposure.

Detecting Exposed Secrets with SecuriSky

SecuriSky, a security scanner for AI-built apps, can help detect exposed secrets in your Next.js application. By automatically scanning your code and identifying potential security issues, SecuriSky can save you time and reduce the risk of security breaches.

Quick Fix Checklist

  • [ ] Store sensitive information in a secure storage solution, such as HashiCorp's Vault.
  • [ ] Avoid exposing environment variables to the client-side using next.config.js.
  • [ ] Use API routes to handle sensitive operations, keeping secrets on the server-side.
  • [ ] Regularly review your code for potential security issues using a tool like SecuriSky.
  • [ ] Implement a secrets management service to securely store and manage sensitive information.
  • Try it free

    Scan your app for these issues now

    Paste your URL and get a full security, performance, and SEO report in under 2 minutes — no signup required.

    Run a free scan