Multiple password fields use z.string().min(12) without .max(). Argon2 verify/hash allocates memory proportional to input — a 100 MB password triggers OOM on a public endpoint.
Evidence
apps/web/src/server/auth.ts:30 — LoginSchema password: z.string().min(1), no .max()
packages/api/src/router/auth.ts:77 — resetPassword .min(12), no .max()
Unauthenticated CPU/memory exhaustion DoS via Argon2 on huge inputs. Argon2 verify blocks the worker thread; concurrent requests saturate CPU.
Proposed Fix
Add .max(128) (OWASP ASVS 2.1.1 bound) to every password Zod schema. Argon2 treats any input >72 bytes identically after pre-hash — a .max(128) bound is safe and eliminates DoS vector.
Acceptance Criteria
All password fields have .max(128) bound
Unit test: POST with 100 KB password returns 400 (validation), not 500
Resolved in main commit 534945f (security: bound password inputs, configure pino redact, patch deps).
packages/api/src/router/user-procedure-support.ts:13,18 caps every password input at z.string().min(12).max(128). Argon2 is no longer reachable with multi-MB inputs — the Zod layer rejects before the hash call. Reset-password, set-password, and user-create paths all share the same schema.
Resolved in main commit 534945f (`security: bound password inputs, configure pino redact, patch deps`).
`packages/api/src/router/user-procedure-support.ts:13,18` caps every password input at `z.string().min(12).max(128)`. Argon2 is no longer reachable with multi-MB inputs — the Zod layer rejects before the hash call. Reset-password, set-password, and user-create paths all share the same schema.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
Multiple password fields use
z.string().min(12)without.max(). Argon2 verify/hash allocates memory proportional to input — a 100 MB password triggers OOM on a public endpoint.Evidence
apps/web/src/server/auth.ts:30 — LoginSchema password: z.string().min(1), no .max()packages/api/src/router/auth.ts:77 — resetPassword .min(12), no .max()packages/api/src/router/invite.ts:112 — acceptInvite password unboundedpackages/api/src/router/user-procedure-support.ts:13,18 — create/set password unboundedImpact
Unauthenticated CPU/memory exhaustion DoS via Argon2 on huge inputs. Argon2 verify blocks the worker thread; concurrent requests saturate CPU.
Proposed Fix
Add
.max(128)(OWASP ASVS 2.1.1 bound) to every password Zod schema. Argon2 treats any input >72 bytes identically after pre-hash — a.max(128)bound is safe and eliminates DoS vector.Acceptance Criteria
.max(128)boundpnpm lint+pnpm test:unitgreenParent Epic: #1
Source: Full-Codebase Security Audit 2026-04-16 (A-1, A-2, B-1)
Resolved in main commit
534945f(security: bound password inputs, configure pino redact, patch deps).packages/api/src/router/user-procedure-support.ts:13,18caps every password input atz.string().min(12).max(128). Argon2 is no longer reachable with multi-MB inputs — the Zod layer rejects before the hash call. Reset-password, set-password, and user-create paths all share the same schema.