Skip to content

CWE-526: Information Exposure Through Environment Variables

Overview

Information exposure through environment variables occurs when applications unintentionally leak sensitive configuration data, credentials, API keys, or system information stored in environment variables. This typically happens through error pages displaying environment dumps, debugging endpoints exposing process state, server-side template injection rendering environment context, or misconfigured logging that captures full environment. Environment variables are a common location for secrets in containerized and cloud environments, making their exposure particularly critical.

OWASP Classification

A02:2025 - Security Misconfiguration

Risk

High: Exposed environment variables often contain database passwords, API keys, encryption keys, OAuth client secrets, AWS credentials, and other sensitive configuration. Attackers can use this information for privilege escalation, lateral movement, data exfiltration, and complete system compromise.

Remediation Steps

Core principle: Never expose environment variables to untrusted users; use secure secret management systems and filter environment data from all user-facing outputs including errors, logs, and debug endpoints.

Remove Debug Endpoints

# VULNERABLE - exposes environment
@app.route('/debug/env')
def debug_env():
    import os
    return jsonify(dict(os.environ))  # DANGEROUS!

# SECURE - remove entirely or protect with authentication
# DELETE THIS ENDPOINT in production

Filter Error Messages

# VULNERABLE - error page shows environment
app.config['DEBUG'] = True  # Shows stack trace + environment!

# SECURE - generic errors, no environment exposure
app.config['DEBUG'] = False

@app.errorhandler(Exception)
def handle_error(e):
    # Log full error server-side (for debugging)
    logger.error(f"Error: {e}", exc_info=True)

    # Return generic error to user
    return {'error': 'Internal server error'}, 500

Use Secret Management Systems

Don't store secrets in environment variables in production:

AWS Secrets Manager:

import boto3

def get_secret(secret_name):
    client = boto3.client('secretsmanager')
    response = client.get_secret_value(SecretId=secret_name)
    return response['SecretString']

db_password = get_secret('prod/db/password')

HashiCorp Vault:

import hvac

client = hvac.Client(url='https://vault.example.com')
secret = client.secrets.kv.v2.read_secret_version(path='prod/database')
db_password = secret['data']['data']['password']

Sanitize Logs

import logging
import re

class SecretFilter(logging.Filter):
    def filter(self, record):
        # Redact common secret patterns
        message = record.getMessage()
        message = re.sub(r'(password|api[_-]?key|token)=[^\s&]+', r'\1=***', message, flags=re.IGNORECASE)
        record.msg = message
        record.args = ()
        return True

logger = logging.getLogger()
logger.addFilter(SecretFilter())

Prevent Server-Side Template Injection

# VULNERABLE - template injection exposes environment
from jinja2 import Template
template = Template(user_input)  # Attacker: {{config.items()}}
output = template.render()

# SECURE - use autoescape, don't render user input as templates
from flask import render_template_string
output = render_template_string('<div>{{ user_data }}</div>', user_data=user_input)

Container Security

For Docker/Kubernetes:

  • Use secrets management (Kubernetes Secrets, Docker secrets)
  • Don't pass secrets via environment variables (use mounted secret files)
  • Scan container images for exposed credentials
  • Use minimal base images
# Kubernetes - use secrets instead of env vars
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: app
    volumeMounts:
    - name: secrets
      mountPath: /etc/secrets
      readOnly: true
  volumes:
  - name: secrets
    secret:
      secretName: app-secrets

Dynamic Scan Guidance

For guidance on remediating this CWE when detected by dynamic (DAST) scanners:

Additional Resources