# Secure defaults enforced in production

- **Pattern:** `ab-002422` (`security-hardening.dependency-security.secure-defaults`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002422
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002422)

## Why it matters

Development conveniences left enabled in production — debug modes, verbose stack traces in error responses, wildcard CORS, authentication bypasses — are a class of security misconfiguration documented by CWE-1188 (Insecure Default Initialization) and OWASP A05 (Security Misconfiguration). NIST 800-53 CM-6 requires baseline configurations to be documented and enforced. A `/api/debug/users` route that bypasses auth and returns all user records, or a `productionBrowserSourceMaps: true` setting that ships full TypeScript source to browsers, represents a failure mode that is easy to introduce during development and easy to forget to remove.

## Severity rationale

Low because insecure defaults don't directly expose data, but they reduce the attacker's effort — verbose errors disclose internals, and disabled auth checks provide direct access.

## Remediation

Gate all development conveniences behind explicit `NODE_ENV` checks and set secure defaults unconditionally in `next.config.ts`:

```ts
// next.config.ts
export default {
  productionBrowserSourceMaps: false,  // No source maps shipped to browsers
  poweredByHeader: false,              // Don't advertise Next.js version
}
```

```ts
// Remove or gate development middleware:
if (process.env.NODE_ENV === 'development') {
  app.use(require('morgan')('dev'))
}

// Default-deny for protected routes:
const PUBLIC_ROUTES = new Set(['/api/auth/login', '/api/health'])
if (!PUBLIC_ROUTES.has(req.path) && !req.user) {
  return res.status(401).json({ error: 'Unauthorized' })
}
```

Search for `if (process.env.NODE_ENV !== 'production')` — any security bypass inside that block is a vulnerability.

## Detection

- **ID:** `secure-defaults`
- **Severity:** `low`
- **What to look for:** List all production configuration settings (debug mode, verbose errors, dev tools, mock auth). For each, check for debug flags, development mode settings, and default credentials that might be active in production. Look for `debug: true` in production configuration, default admin passwords documented in README or code comments, development middleware (CORS wildcard, verbose logging) that might be active in production, and disabled authentication for convenience that was never re-enabled.
- **Pass criteria:** Debug mode is disabled in production. No default or documented credentials accepted in production. Development middleware is gated behind environment checks. Authentication is required by default for protected routes — 100% of settings must use secure values in production (debug disabled, verbose errors off). Report: "X production settings verified, all Y use secure defaults."
- **Fail criteria:** Debug mode enabled unconditionally. Default admin credentials accepted. Development shortcuts (skip auth, accept any CORS origin) active in production.
- **Skip (N/A) when:** Never — secure defaults apply to all production applications.
- **Detail on fail:** `"next.config.ts has productionBrowserSourceMaps: true — full source maps served in production"` or `"Debug endpoint /api/debug/users returns all user data without auth check"`
- **Remediation:** Gate all development conveniences behind explicit environment checks:

  ```ts
  // next.config.ts
  const nextConfig = {
    productionBrowserSourceMaps: false,  // No source maps in production
    poweredByHeader: false,              // Don't advertise Next.js version
  }

  // Development-only middleware
  if (process.env.NODE_ENV === 'development') {
    app.use(require('morgan')('dev'))    // Verbose logging in dev only
  }

  // Require explicit opt-in for public routes
  const isPublicRoute = PUBLIC_ROUTES.has(req.path)
  if (!isPublicRoute && !req.user) return res.status(401).json({ error: 'Unauthorized' })
  ```

---

## External references

- cwe CWE-1188
- owasp A05
- nist CM-6

Taxons: operational-readiness

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