This vulnerability occurs when sensitive information stored in environment variables (like database passwords, API keys, secret keys) is exposed to unauthorized parties. This often happens due to misconfigurations that reveal server environment details, such as:
Enabling debug modes that display all environment variables on error pages (e.g., Django debug page, Laravel Ignition).
Misconfigured serverless function bindings or logging that include the full environment.
Client-side JavaScript accessing environment variables that were incorrectly bundled or exposed during the build process (common in frontend frameworks). 🖥️➡️🔓
This is primarily a configuration and deployment issue. While frameworks rely on environment variables for secure configuration, the leak happens when the environment itself is exposed.Key Remediation Principles:
Disable Debug Modes in Production: Ensure DEBUG=False, APP_DEBUG=false, ASPNETCORE_ENVIRONMENT=Production, NODE_ENV=production, etc. (See CWE-11).
Remove Diagnostic Scripts: Never leave scripts like phpinfo() accessible on production servers.
Secure Logging: Configure logging to avoid dumping all environment variables.
Restrict Server Info: Configure web servers (Nginx, Apache) not to reveal detailed version or environment information in headers or error pages.
Secure Frontend Builds:Never embed server-side secrets directly into client-side JavaScript bundles. Use server-side rendering or dedicated API endpoints to handle sensitive operations. Prefix environment variables intended for the browser (e.g., NEXT_PUBLIC_, VITE_) and ensure only non-sensitive values are exposed this way.
Django’s debug page (DEBUG = True) displays all settings, including those loaded from environment variables. Flask debug mode can also expose environment details.
Check production settings.py or environment variables to ensure DEBUG is False. Trigger an error in production and verify the generic error page appears, not the detailed Django debug page. Review application logs to ensure os.environ or sensitive individual variables are not being logged.
Spring Boot’s Actuator /env endpoint (if unsecured) or detailed error pages (server.error.include-stacktrace=always) can expose environment variables and system properties.
# application.properties# Load secrets from env vars (good practice)db.password=${DB_PASSWORD}aws.secret.key=${AWS_SECRET_ACCESS_KEY}# DANGEROUS: Exposing all actuator endpoints without security.management.endpoints.web.exposure.include=*# management.endpoint.env.enabled=true (Default)# If Spring Security is misconfigured or not applied to /actuator/**
Attacker browses to /actuator/env and sees all environment variables, including DB_PASSWORD and AWS_SECRET_ACCESS_KEY.
Vulnerable Scenario 2: Leaking via Error Message (Less Direct)
While less common for direct env var dumps, verbose stack traces enabled by server.error.include-stacktrace=always might sometimes reveal configuration property values derived from environment variables within the trace details.
Secure Actuator: Set management.endpoints.web.exposure.include to expose only necessary endpoints (e.g., health, info) and secure sensitive ones (like env, heapdump) using Spring Security. Set specific credentials for the actuator endpoints.
# application-production.properties (Secure Actuator Config)# Expose only health and info publiclymanagement.endpoints.web.exposure.include=health,info# Expose others via a different port or path secured by Spring Security# management.server.port=9090 # Example separate port# management.endpoint.env.enabled=true # Keep enabled if needed for secured access# Secure error handlingserver.error.include-stacktrace=neverserver.error.whitelabel.enabled=false
// config/SecurityConfig.java (Example securing Actuator)// Add configuration to require ADMIN role for /actuator/** endpoints,// potentially using a separate WebSecurityConfigurerAdapter with @Order.@Configuration@Order(1) // Example orderpublic class ActuatorSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.requestMatcher(EndpointRequest.toAnyEndpoint()) // Selects actuator endpoints .authorizeRequests() .requestMatchers(EndpointRequest.to("health", "info")).permitAll() // Allow health/info .anyRequest().hasRole("ACTUATOR_ADMIN") // Secure others .and() .httpBasic(); // Use basic auth for actuator access } // Configure users/authentication for ACTUATOR_ADMIN role separately}
Check application.properties for management.endpoints.web.exposure.include. Try accessing /actuator/env and other sensitive actuator endpoints in production – they should require authentication or be disabled. Trigger errors to ensure stack traces are suppressed. Review logs for environment variable dumps.
ASP.NET Core Developer Exception Page (app.UseDeveloperExceptionPage()) shows request details, which might include environment variables under certain conditions (less common than direct display). Misconfigured logging or direct dumping of IConfiguration can also leak info.
Vulnerable Scenario 1: Developer Exception Page in Production
As covered in CWE-11, if ASPNETCORE_ENVIRONMENT=Development, the detailed error page is shown. While it doesn’t directly list all environment variables like Django’s, it reveals a lot of internal state that might indirectly expose configuration sourced from environment variables.
// Startup.cs - Configure()public void Configure(IApplicationBuilder app, IWebHostEnvironment env){ // DANGEROUS: If env is Development in production. if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); // Shows rich debug info } else { /* ... */ } // ...}
A developer logs the entire configuration object for debugging.
// Some Service Constructor or Methodpublic MyService(IConfiguration config, ILogger<MyService> logger){ // DANGEROUS: Logging the entire configuration tree, // which includes values from appsettings.json, environment variables, Key Vault etc. logger.LogDebug("Current Configuration: {ConfigSnapshot}", config.AsEnumerable()); // ...}
Ensure ASPNETCORE_ENVIRONMENT=Production and UseExceptionHandler is used (See CWE-11).
Avoid logging the entire IConfiguration object. Log specific, non-sensitive configuration keys if necessary.
Use secrets management tools (User Secrets, Key Vault) which integrate with IConfiguration but keep secrets out of easily viewable environment variables where possible.
Check ASPNETCORE_ENVIRONMENT in production. Trigger errors and ensure the developer exception page is not shown. Review logging code and output to ensure IConfiguration or sensitive individual config values sourced from environment variables are not logged.
Vulnerable Scenario 1: Laravel APP_DEBUG=true in Production
# .env (Production)APP_ENV=production# DANGEROUS: Ignition error page will show .env contents and server variables.APP_DEBUG=trueDB_PASSWORD=ProdDbPassword!AWS_SECRET_ACCESS_KEY=ProdAwsSecretKey
A developer uploads a file info.php containing <?php phpinfo(); ?> to the server for debugging and forgets to remove it.
// info.php (DANGEROUS if accessible on production server)<?php// This function outputs extensive information including all// environment variables, PHP settings, server variables, etc.phpinfo();?>
Attacker browses to https://yourdomain.com/info.php
# .env (Laravel Production - Secure)APP_ENV=productionAPP_DEBUG=false # SECURELOG_CHANNEL=stack# Secrets are loaded but not exposed by debug screensDB_PASSWORD=ProdDbPassword!AWS_SECRET_ACCESS_KEY=ProdAwsSecretKey
Check APP_DEBUG setting in production .env. Trigger errors in Laravel; ensure Ignition debug page is replaced by the generic error view. Scan the web root for files containing phpinfo() and attempt to access them. Check web server config denies access to .env.
Vulnerable Scenario 1: Leaking process.env in Error Handler
// app.js (Error Handler)const isProd = (process.env.NODE_ENV === 'production');app.use((err, req, res, next) => { console.error(err); // Log server-side // DANGEROUS: Sending the whole process.env in development mode, // which might accidentally run in production if NODE_ENV isn't set correctly. res.status(err.status || 500).json({ message: err.message, // Exposing all environment variables is risky even in dev, let alone prod. environment: isProd ? undefined : process.env });});
Vulnerable Scenario 2: Bundling Server Secrets into Frontend Code
Using frontend frameworks (React, Vue, Angular) with build tools (Webpack, Vite) where server-side environment variables (like API_SECRET) are not correctly excluded and get embedded in the compiled JavaScript sent to the browser.
// webpack.config.js (Example - Incorrect Usage)const webpack = require('webpack');// DANGEROUS: Directly embedding a sensitive server-side key into client bundle.// Attacker can just view the source of the JS file.module.exports = { // ... other config ... plugins: [ new webpack.DefinePlugin({ 'process.env.API_SECRET': JSON.stringify(process.env.API_SECRET_SERVER_ONLY) }) ]};
Configure error handlers never to send process.env or sensitive parts of it to the client.
Crucially for frontends: Only expose non-sensitive, public configuration variables to the frontend build. Use naming conventions (like REACT_APP_, VITE_, NEXT_PUBLIC_) enforced by the build tools. Secrets needed for API calls must remain on the server; the frontend should call backend endpoints that use the secrets internally.
Check NODE_ENV in production. Trigger errors and inspect responses for environment data. Inspect the bundled JavaScript files sent to the browser (view source, check network tab). Search the JS code for any hardcoded API keys, secrets, or environment variables that should be server-side only. Check build configurations (webpack.config.js, vite.config.js) for incorrect injection of server-side variables.
Rails debug exceptions page (config.consider_all_requests_local = true) shows request environment details, which can include server environment variables. Accidentally exposing ENV in logs or views.
Check config/environments/production.rb for consider_all_requests_local = false. Trigger errors and verify the generic error page is shown. Review code and logs for any dumps of the ENV hash or sensitive individual environment variables.