Security [HIGH]: Login timing attack enables user-email enumeration #40
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
authorize()returns early for unknown users (no argon2 call) and runs argon2.verify for known users. Response time differs by >100 ms. Audit-log messages differ (user not foundvsinvalid password). An attacker can enumerate which emails exist without any rate-limit distinction.Evidence
apps/web/src/server/auth.ts:70-82 — early return null on user-not-found (no argon2 call)apps/web/src/server/auth.ts:100 — argon2 verify only on known userapps/web/src/server/auth.ts:73,88 — differing audit summariesImpact
User-enumeration: attacker builds list of valid emails (HR leak, phishing target list). Combined with the rate-limit finding, enables targeted attacks.
Proposed Fix
Run dummy argon2.verify against a persistent dummy-hash when user is not found, ensuring identical response time. Unify audit-log summaries to
Login failedwithout distinguishing reason (or log reason only at DEBUG level).Acceptance Criteria
Parent Epic: #1
Source: Full-Codebase Security Audit 2026-04-16 (A-5)
Resolved in commit
0303063(security: constant-time authorize + uniform audit summaries). Authorize path now runs Argon2 verify against a dummy hash when the user is missing, and audit summaries no longer leak existence. No timing side-channel.