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.
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.
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.
// 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.
ID: ecommerce-pci.access-control.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):
// 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:
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);
}