Security [CRITICAL]: Unbounded password inputs enable Argon2 DoS #36
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
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.