security: reject common/weak passwords on every set-password path (#31) #60

Open
Hartmut wants to merge 2 commits from security/password-policy-blacklist into main
Owner

Summary

  • Adds a synchronous checkPasswordPolicy() in @capakraken/shared that rejects common-list, trivial-pattern, sequential, and identity-containing passwords
  • Wires the check into all five password-mutation sites: first-admin setup, admin createUser, admin setUserPassword, invite acceptance, and password-reset
  • 17 unit tests covering length bounds, repeats, sequences, blacklist (case-insensitive), and identity inclusion

What this blocks

  • >=12-char dictionary entries that would pass the length gate (rockyou top, predictable seasonal/admin-default patterns)
  • Trivial constructions: aaaaaaaaaaaa, abcabcabcabc, keyboard runs like abcdefghijkl
  • Passwords that include the user's email local-part or any name component (substrings >= 4 chars, case-insensitive)

Why

CDP epic #1 — addresses the open \ud83d\udd34 Block commonly chosen passwords item in #31. Active password-expiry tracking (passwordChangedAt on the User model + admin-configurable max age) is intentionally out of scope here and will land as a follow-up so this PR stays additive and migration-free.

Test plan

  • pnpm --filter @capakraken/shared exec vitest run (279 pass, +17 new)
  • pnpm --filter @capakraken/api exec vitest run (1945 pass)
  • pnpm --filter @capakraken/web exec vitest run (1285 pass)
  • pnpm --filter @capakraken/{web,api,shared} exec tsc --noEmit clean
  • pnpm lint clean (0 errors)
## Summary - Adds a synchronous `checkPasswordPolicy()` in `@capakraken/shared` that rejects common-list, trivial-pattern, sequential, and identity-containing passwords - Wires the check into all five password-mutation sites: first-admin setup, admin createUser, admin setUserPassword, invite acceptance, and password-reset - 17 unit tests covering length bounds, repeats, sequences, blacklist (case-insensitive), and identity inclusion ## What this blocks - `>=12`-char dictionary entries that would pass the length gate (rockyou top, predictable seasonal/admin-default patterns) - Trivial constructions: `aaaaaaaaaaaa`, `abcabcabcabc`, keyboard runs like `abcdefghijkl` - Passwords that include the user's email local-part or any name component (substrings >= 4 chars, case-insensitive) ## Why CDP epic #1 — addresses the open `\ud83d\udd34 Block commonly chosen passwords` item in #31. Active password-expiry tracking (`passwordChangedAt` on the `User` model + admin-configurable max age) is intentionally out of scope here and will land as a follow-up so this PR stays additive and migration-free. ## Test plan - [x] `pnpm --filter @capakraken/shared exec vitest run` (279 pass, +17 new) - [x] `pnpm --filter @capakraken/api exec vitest run` (1945 pass) - [x] `pnpm --filter @capakraken/web exec vitest run` (1285 pass) - [x] `pnpm --filter @capakraken/{web,api,shared} exec tsc --noEmit` clean - [x] `pnpm lint` clean (0 errors)
Hartmut added 1 commit 2026-04-18 14:09:52 +02:00
security: reject common/weak passwords on every set-password path (#31)
CI / Architecture Guardrails (pull_request) Successful in 6m31s
CI / Typecheck (pull_request) Failing after 6m9s
CI / Build (pull_request) Has been skipped
CI / E2E Tests (pull_request) Has been skipped
CI / Fresh-Linux Docker Deploy (pull_request) Has been skipped
CI / Assistant Split Regression (pull_request) Successful in 7m23s
CI / Lint (pull_request) Successful in 6m54s
CI / Unit Tests (pull_request) Successful in 9m28s
CI / Release Images (pull_request) Has been skipped
e01074926e
Adds a synchronous policy check that blocks (1) the curated >=12-char
common-password list (rockyou top, predictable seasonal, admin defaults),
(2) trivial patterns (single-char repeat, short-pattern repeat, keyboard
or numeric sequences), and (3) passwords containing the user's email
local-part or any name component. Wired into all five password-mutation
sites: first-admin setup, admin createUser/setUserPassword, invite
acceptance, and password-reset.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Hartmut force-pushed security/password-policy-blacklist from 9ef7114c77 to e01074926e 2026-04-18 14:09:52 +02:00 Compare
Hartmut added 1 commit 2026-04-18 14:53:35 +02:00
test(shared): narrow PasswordCheckResult before reading reason
CI / Architecture Guardrails (pull_request) Successful in 6m11s
CI / Assistant Split Regression (pull_request) Successful in 7m19s
CI / Lint (pull_request) Successful in 7m59s
CI / Typecheck (pull_request) Successful in 9m28s
CI / Build (pull_request) Successful in 6m53s
CI / E2E Tests (pull_request) Successful in 6m7s
CI / Fresh-Linux Docker Deploy (pull_request) Successful in 6m52s
CI / Release Images (pull_request) Has been skipped
CI / Unit Tests (pull_request) Successful in 8m30s
cfce1f2a15
CI typecheck failed because the discriminated union returned by
checkPasswordPolicy only exposes `reason` on the `{ ok: false }` branch.
Guard each `.reason` assertion with `if (!result.ok)` so the test file
typechecks under exactOptionalPropertyTypes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Some checks are pending
CI / Architecture Guardrails (pull_request) Successful in 6m11s
CI / Assistant Split Regression (pull_request) Successful in 7m19s
CI / Lint (pull_request) Successful in 7m59s
CI / Typecheck (pull_request) Successful in 9m28s
CI / Build (pull_request) Successful in 6m53s
CI / E2E Tests (pull_request) Successful in 6m7s
CI / Fresh-Linux Docker Deploy (pull_request) Successful in 6m52s
CI / Release Images (pull_request) Has been skipped
CI / Unit Tests (pull_request) Successful in 8m30s
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin security/password-policy-blacklist:security/password-policy-blacklist
git checkout security/password-policy-blacklist
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Hartmut/CapaKraken#60