# Feature flags are environment-specific

- **Pattern:** `ab-001266` (`environment-security.environment-isolation.feature-flags`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001266
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001266)

## Why it matters

Feature flags hardcoded in source code or set to the same value across all environments create two distinct risks: debug panels, admin shortcuts, and incomplete features ship to production, and toggling them requires a code change and redeployment rather than a configuration update. OWASP A05 (Security Misconfiguration) and CWE-1188 both flag hardcoded defaults as a misconfiguration class. A debug panel exposed in production can leak stack traces, internal routes, or database query details. A payment feature flag stuck at `true` in staging that also runs in production will charge real customers for test transactions.

## Severity rationale

Medium because hardcoded feature flags allow debug or incomplete features to surface in production, where they can expose internal system details or trigger unintended behavior.

## Remediation

Replace hardcoded flag values with environment variable checks or a feature flag service. The flag evaluation must differ between environments — checking only `NODE_ENV` is sufficient for simple cases; use a service like LaunchDarkly or Unleash for runtime toggling without redeployment.

```ts
// BEFORE (wrong)
const DEBUG_MODE = true

// AFTER (correct) — environment variable + NODE_ENV guard
const DEBUG_MODE =
  process.env.NODE_ENV !== 'production' &&
  process.env.ENABLE_DEBUG === 'true'

// AFTER (correct) — feature flag service
import { isEnabled } from '@unleash/nextjs'
const debugEnabled = await isEnabled('debug-panel')
```

Verify that every flag evaluates to `false` in production by running the production config locally and asserting against each flag name.

## Detection

- **ID:** `feature-flags`
- **Severity:** `medium`
- **What to look for:** Look for feature flag configuration in the codebase. Check if flags are environment-aware (using `process.env.NODE_ENV` or environment variable checks). Verify disabled features are not accessible in production (no debug panels, no feature previews, no test routes).
- **Pass criteria:** Enumerate all feature flags found in the codebase. Feature flags are configured per environment with at least 100% using environment variables or a flag service. Disabled features are not rendered in production. Feature flag state is not hardcoded.
- **Fail criteria:** Feature flags are hardcoded in source, or debug/test features are accessible in production.
- **Skip (N/A) when:** The project does not use feature flags.
- **Detail on fail:** `"Feature flags hardcoded to true for all environments"` or `"Debug panel accessible in production via /debug route"`.
- **Remediation:** Move feature flags to environment configuration:

  ```ts
  // BEFORE (wrong)
  const DEBUG_MODE = true  // hardcoded

  // AFTER (correct)
  const DEBUG_MODE = process.env.NODE_ENV !== 'production' && process.env.ENABLE_DEBUG === 'true'
  ```

  Or use a feature flag service:
  ```ts
  import { getFeatureFlag } from '@launchdarkly/node-server-sdk'
  const debugEnabled = await getFeatureFlag(client, 'debug-panel', context)
  ```

## External references

- cwe CWE-1188
- owasp A05

Taxons: placeholder-hygiene, operational-readiness

HTML version: https://auditbuffet.com/patterns/ab-001266
