# Password policy enforces minimum complexity and rotation

- **Pattern:** `ab-001184` (`ecommerce-pci.access-control.password-policy`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001184
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001184)

## Why it matters

PCI-DSS 4.0 Req 8.3.6 sets the minimum password complexity requirements; Req 8.3 requires strong authentication for all user IDs. A minimum password length of 6 characters with no complexity rules is crackable in seconds with commodity GPU rigs and common wordlists. CWE-521 (Weak Password Requirements) and OWASP A07 (Identification and Authentication Failures) both identify inadequate password policy as a direct authentication failure. NIST IA-5 provides the baseline: minimum 8 characters, not in a known compromised password list. Admin accounts with weak passwords in a CDE represent a trivial brute-force vector.

## Severity rationale

Low because weak password policy increases susceptibility to brute-force and credential-stuffing attacks but is mitigated in part by account lockout and MFA — it raises risk without being an immediate critical vector on its own.

## Remediation

Configure minimum 12 characters with uppercase, lowercase, numbers, and symbols enforced at the auth provider level — not just in client-side validation that can be bypassed. Add a 90-day rotation reminder for admin accounts per PCI-DSS 4.0 Req 8.3.6.

```typescript
// src/lib/auth/validate-password.ts
export function validatePassword(pw: string): boolean {
  return (
    pw.length >= 12 &&
    /[A-Z]/.test(pw) &&
    /[a-z]/.test(pw) &&
    /\d/.test(pw) &&
    /[!@#$%^&*()_+\-=\[\]{};'",./<>?]/.test(pw)
  );
}
```

For Supabase, set the password policy in the Auth dashboard under Authentication > Policies. For custom auth, call `validatePassword()` on the server side before hashing — never trust the client to enforce this.

## Detection

- **ID:** `password-policy`
- **Severity:** `low`
- **What to look for:** Count the number of password complexity requirements enforced in code or auth provider config. Check for minimum length (must be at least 8 characters, recommended 12), uppercase requirement, lowercase requirement, number requirement, symbol requirement. Look for password rotation settings (e.g., 90-day expiry for admin accounts). Enumerate all password validation functions or auth provider policy configurations found.
- **Pass criteria:** Password policy enforces at least 4 of 5 complexity requirements: (1) minimum 8 characters, (2) uppercase letters, (3) lowercase letters, (4) numbers, (5) symbols. At least 1 reference to password rotation or expiry for admin accounts exists. Policy is either coded in a validation function or configured in the auth provider dashboard (with evidence in code). Report: "X of 5 complexity requirements enforced, rotation: yes/no."
- **Fail criteria:** Fewer than 4 complexity requirements enforced, or minimum password length is under 8 characters, or no documented password policy exists anywhere in code or configuration.
- **Skip (N/A) when:** Using passwordless auth only (no password fields — only OAuth, magic links, or WebAuthn; confirm by checking auth provider config and login UI).
- **Detail on fail:** Specify the policy gap. Example: `"Password validation function enforces 2 of 5 requirements (length and lowercase only). No rotation configured."` or `"Auth provider configured with minimum 6 characters, no symbol requirement. 0 rotation references found."`
- **Remediation:** Configure password policy in your auth provider. For Supabase (via dashboard or API):

  ```typescript
  // Set password policy requirements
  const passwordPolicy = {
    minLength: 12,
    pattern: {
      uppercase: true,
      lowercase: true,
      numbers: true,
      symbols: true,
    },
    rotation: {
      interval: 90, // days, for admin users
      noticeInterval: 14, // days before expiry
    },
  };
  ```

  For custom auth, validate passwords:
  ```typescript
  function validatePassword(password) {
    const requirements = {
      minLength: password.length >= 12,
      hasUppercase: /[A-Z]/.test(password),
      hasLowercase: /[a-z]/.test(password),
      hasNumbers: /\d/.test(password),
      hasSymbols: /[!@#$%^&*()_+\-=\[\]{};:'",.<>?]/.test(password),
    };
    return Object.values(requirements).every(v => v);
  }
  ```

## External references

- pci-dss Req 8.3
- pci-dss Req 8.3.6
- cwe CWE-521
- owasp A07
- nist IA-5

Taxons: access-control, regulatory-conformance

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