> ## Documentation Index
> Fetch the complete documentation index at: https://guide.codepure.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Environment Files (.env)

> Securing environment variables and .env files

## Common Misconfiguration

Committed `.env` files expose all application secrets including API keys, database passwords, and encryption keys. 😱

### Vulnerable Example

```bash theme={null}
# VULNERABLE - .env file with secrets
# File: .env (committed to repository)

# Database
DATABASE_URL=postgresql://admin:SuperSecret123!@db.prod.example.com:5432/production
REDIS_PASSWORD=Redis@Pass2024!

# API Keys
STRIPE_SECRET_KEY=sk_live_4eC39HqLyjWDarjtT1zdp7dcTYooMQauvdEDq54
SENDGRID_API_KEY=SG.actual_api_key_here_never_commit_this
JWT_SECRET=my-super-secret-jwt-key-that-should-be-random

# AWS
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

# OAuth
GOOGLE_CLIENT_SECRET=GOCSPX-1234567890abcdefghijklm
GITHUB_CLIENT_SECRET=1234567890abcdef1234567890abcdef12345678

# Encryption
ENCRYPTION_KEY=32_byte_encryption_key_here_abc123
APP_SECRET=change_me_to_something_random_and_secret

# Admin
ADMIN_PASSWORD=admin123
SUPER_USER_TOKEN=super_secret_admin_token
```

```javascript theme={null}
// VULNERABLE - Loading .env without validation
require('dotenv').config();

const dbConnection = process.env.DATABASE_URL; // Directly used
const apiKey = process.env.API_KEY; // No validation

// Logging environment variables (exposes secrets)
console.log('Environment:', process.env);
```

## Secure Example

```bash theme={null}
# SECURE - .env.example (committed to repository)
# Copy this file to .env and fill in your values

# Database
DATABASE_URL=postgresql://username:password@host:port/database
REDIS_PASSWORD=

# API Keys (obtain from respective services)
STRIPE_SECRET_KEY=sk_live_...
SENDGRID_API_KEY=SG....
JWT_SECRET= # Generate with: openssl rand -base64 32

# AWS (use IAM roles in production)
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

# OAuth
GOOGLE_CLIENT_SECRET=
GITHUB_CLIENT_SECRET=

# Encryption (generate secure random keys)
ENCRYPTION_KEY= # Generate with: openssl rand -hex 32
APP_SECRET=

# Admin
ADMIN_PASSWORD= # Use strong password
SUPER_USER_TOKEN= # Generate with: uuidgen
```

```javascript theme={null}
// SECURE - Proper environment variable handling
const dotenv = require('dotenv');
const crypto = require('crypto');

class ConfigManager {
    constructor() {
        this.loadEnvironment();
        this.validateConfig();
    }

    loadEnvironment() {
        // Load .env file only in development
        if (process.env.NODE_ENV !== 'production') {
            const result = dotenv.config();
            if (result.error) {
                console.warn('Warning: .env file not found');
            }
        }
        // In production, variables should be injected by the environment
        // (e.g., Docker secrets, Kubernetes secrets, PaaS config vars)
    }

    validateConfig() {
        const required = [
            'DATABASE_URL',
            'JWT_SECRET',
            'ENCRYPTION_KEY'
        ];

        const missing = required.filter(key => !process.env[key]);

        if (missing.length > 0) {
            throw new Error(`Missing required environment variables: ${missing.join(', ')}`);
        }

        // Validate format and strength
        this.validateDatabaseUrl();
        this.validateSecrets();
    }

    validateDatabaseUrl() {
        const dbUrl = process.env.DATABASE_URL;
        try {
            const url = new URL(dbUrl);
            // Example strength check (adjust as needed)
            if (!url.password || url.password.length < 12) {
                console.warn('Warning: Database password seems weak');
            }
        } catch (error) {
            throw new Error(`Invalid DATABASE_URL format: ${error.message}`);
        }
    }

    validateSecrets() {
        // Check JWT secret strength
        const jwtSecret = process.env.JWT_SECRET;
        if (!jwtSecret || jwtSecret.length < 32) {
            throw new Error('JWT_SECRET must be at least 32 characters');
        }

        // Check encryption key format (e.g., 64 hex chars for AES-256)
        const encKey = process.env.ENCRYPTION_KEY;
        if (!encKey || !/^[0-9a-fA-F]{64}$/.test(encKey)) {
            throw new Error('ENCRYPTION_KEY must be 64 hex characters (32 bytes)');
        }
    }

    getConfig() {
        // Return structured config, ensuring secrets aren't accidentally logged
        return {
            database: {
                url: process.env.DATABASE_URL,
                ssl: process.env.NODE_ENV === 'production'
            },
            jwt: {
                secret: process.env.JWT_SECRET,
                expiresIn: '15m' // Keep short
            },
            encryption: {
                key: Buffer.from(process.env.ENCRYPTION_KEY, 'hex'),
                algorithm: 'aes-256-gcm'
            }
            // Add other non-sensitive config values here
        };
    }
}
```

```yaml theme={null}
# SECURE - Docker compose with secrets management
version: '3.8'

services:
  app:
    image: myapp:latest
    environment:
      - NODE_ENV=production
      # Inject secrets via files mounted by Docker
      - DATABASE_URL_FILE=/run/secrets/db_url
      - JWT_SECRET_FILE=/run/secrets/jwt_secret
    secrets:
      - db_url
      - jwt_secret

secrets:
  db_url:
    # Use Docker Swarm secrets or bind-mount from secure location
    external: true # Assumes 'db_url_v1' secret exists
    name: db_url_v1
  jwt_secret:
    external: true # Assumes 'jwt_secret_prod' secret exists
    name: jwt_secret_prod
```

***

## Detection Patterns

* Generic Secret: `` `(?i)(password|passwd|pwd|secret|token|api.?key)\s*[:=]\s*['"]?[^'"\s]+['"]?` ``
* AWS Key: `` `(AWS|aws|Aws)_(ACCESS|access|Access)_KEY(_ID)?\s*[:=]\s*['"]?(AKIA|ASIA)[0-9A-Z]{16}['"]?` ``
* AWS Secret: `` `(AWS|aws|Aws)_(SECRET|secret|Secret)_ACCESS_KEY\s*[:=]\s*['"]?[A-Za-z0-9/+=]{40}['"]?` ``
* Stripe Key: `` `STRIPE_(SECRET|secret|Secret)_KEY\s*[:=]\s*['"]?sk_(live|test)_[0-9a-zA-Z]{24,}['"]?` ``
* Google OAuth Secret: `` `(GOOGLE|google|Google)_CLIENT_SECRET\s*[:=]\s*['"]?GOCSPX-[0-9a-zA-Z-]{30,}['"]?` ``

***

## Prevention Best Practices

1. **Never Commit `.env` Files:** This is the absolute **most important rule** 🚫. Add `.env` (and similar files like `.envrc`, `.flaskenv`) to your `.gitignore` file immediately. Secrets should never exist in your code repository's history.
2. **Use `.env.example`:** Commit a template file (e.g., `.env.example`) that lists all required environment variables but **without** their actual values. This guides other developers (and your future self) on what needs to be configured.
3. **Validate Variables on Startup:** Your application should check for the *presence* and potentially the *format* or *strength* of required environment variables when it starts. Fail fast if critical secrets are missing or invalid.
4. **Use Secrets Management in Production:** While `.env` files are okay for local development, they are **not** suitable for production. Use platform-native solutions (like AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, Kubernetes Secrets, Docker Secrets, Heroku Config Vars) to inject secrets securely into your production environment.
5. **Encrypt Sensitive Variables:** For secrets stored *at rest* (e.g., in some deployment configurations or backups), ensure they are encrypted. Tools like `sops` can encrypt secrets within configuration files, decrypting them only at runtime.
6. **Implement Proper Access Controls:** Limit who can access the production environment where secrets are stored or injected. Use Role-Based Access Control (RBAC) on your cloud platform or orchestrator.
7. **Rotate Secrets Regularly:** All secrets (database passwords, API keys, encryption keys) should have a defined lifespan and be rotated periodically. Automate this process using secrets management tools.
8. **Use Different Secrets Per Environment:** Never share secrets between development, staging, and production. Each environment must have its own unique set of credentials.
9. **Scan Repositories for Secrets:** Use automated tools (like `git-secrets`, `truffleHog`, or GitHub Advanced Security secret scanning) in your CI/CD pipeline to detect accidentally committed secrets before they are merged.
