# password policy that isn't security theater

## TL;DR

Follow the NIST playbook: require length (12 to 15 characters minimum), drop complexity rules and forced rotation, screen new passwords against breached-password lists, and put MFA on everything that matters. Complexity rules produce `Password1!` on a sticky note; length plus breach screening produces passwords that survive real attacks.

```text
password policy that isn't security theater
```

## Use this when

- You are writing or revising your org's password policy
- An audit flagged your password rules (or lack of them)
- You want to kill forced 90-day rotation and need the justification
- Users are rebelling against the current rules

## Not for this skill when

- You need the MFA rollout mechanics (different skill)
- You are choosing a password manager for the team
- The question is about API keys or service credentials (those shouldnt be passwords at all)

## Steps

### 1. Replace complexity rules with a length minimum

Delete the "one uppercase, one number, one symbol" rule. Set a minimum of 12 characters (15 for privileged accounts) and allow spaces so passphrases work. Length beats character-set games by orders of magnitude.

```bash
printf 'Minimum length: 12 (15 for admins)\nComplexity rules: none\nPassphrases allowed: yes\n' | tee password-policy.txt
```

Expected: a policy file stating the new rule. If your system enforces complexity and cant be reconfigured, document the exception and put that system on the replace list.

### 2. Screen new passwords against breached lists

A long password from a breach is already dead. Check the SHA-1 prefix via the breached-passwords API (k-anonymity keeps the full hash local).

```bash
printf '%s' '[candidate-password]' | sha1sum | cut -c1-5 | xargs -I{} curl -s https://api.pwnedpasswords.com/range/{} | grep -i $(printf '%s' '[candidate-password]' | sha1sum | cut -c6-40 | tr 'a-z' 'A-Z')
```

Expected: no output means the password wasnt found in the breach corpus; any match means reject it and pick another. In production, do this check server-side at password-set time, not as a shell one-liner.

### 3. End forced rotation, keep compromise-driven changes

Scheduled expiry makes passwords weaker (people iterate `winter2026!` to `spring2026!`) and trains users to hate security. Change passwords on compromise, on suspected breach, or when the breached-list check fails, not on a calendar.

```bash
printf 'Rotation: on compromise or suspected breach only\nScheduled expiry: disabled\n' | tee -a password-policy.txt
```

Expected: the policy explicitly bans calendar rotation. When auditors ask, cite NIST 800-63B; it is on your side here.

### 4. Require MFA everywhere the password matters

Any system holding sensitive data or admin capability gets MFA regardless of password quality. A great password policy without MFA is one phishing email from failure.

```bash
printf 'MFA required: all admin consoles, VPN, email, code hosting, cloud consoles\n' | tee -a password-policy.txt
```

Expected: the list of MFA-mandatory systems in the policy. If a system cant do MFA, it goes on the risk register with a mitigation and a replacement timeline.

### 5. Give people a password manager and measure adoption

Humans cant memorize 80 unique passwords, so without a manager they reuse. Provide one, enroll at onboarding, and track adoption like any rollout.

```bash
printf 'Password manager: [product] | enrolled: [count]/[total] | target: 100 percent of staff\n' | tee -a password-policy.txt
```

Expected: adoption tracked like any other rollout. The policy works when the tooling makes the secure choice the easy choice.

### Variant: nist password guidelines summary

The 30-second version: minimum 8 characters (we recommend 12+), allow 64, no complexity rules, check against known-bad lists, no periodic expiry, MFA. Thats the whole standard as it applies to policy writing.

### Variant: password complexity vs length

The math: each added character multiplies the search space by the alphabet size, while complexity rules just annoy users into predictable patterns. A 16-character passphrase of plain words beats an 8-character symbol salad that gets written on a sticky note.

### Variant: how to justify killing password expiration to auditors

Bring the NIST 800-63B section, your breach-screening control, and incident data showing resets happen around compromises anyway.

## Why this happens

Old password rules were designed when attackers guessed by hand and breaches were rare. Now attackers work from breach corpuses of billions of passwords, so the defenses that matter are uniqueness (breach screening) and a second factor (MFA), not character gymnastics. Theater rules persist because "weve always done it this way" is easier than reading the current guidance.

## Edge cases and pitfalls

- Legacy systems with max lengths: some old systems cap at 8 or 16 characters; document them as exceptions and isolate them behind MFA or network controls.
- The breached-list check on login: checking at set-time is required; checking at login-time too catches passwords breached after they were set.
- Shared accounts: no password policy fixes a shared admin login; give every human their own account and kill the shared one.
- Password hints and security questions: these are just weak backup passwords; disable them wherever MFA or email recovery exists.
- Phone friction: long passphrases annoy on mobile; thats an argument for passkeys and MFA, not shorter passwords.
- Compliance frameworks lagging: some older frameworks still demand rotation; implement the compensating controls and document the deviation rather than following a rule you know is harmful.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_LujoJ0miL0mlxgvVKHxC4A
