p1-password-reset-rate-limits

readytype/backlogpriority/p1severity/mediumtopic/authtopic/rate-limit

p1 ยท Password reset rate limits (3/h email + IP)

TL;DR

Replace the current generalRateLimiter (10/min per email only) on requestPasswordReset with audit-spec limits: 3 requests/hour per email and 5 requests/hour per IP, without breaking enumeration-safe generic success responses.

Description

  • Problem: src/lib/actions/passwordReset.ts uses generalRateLimiter (10 attempts / 1 minute, email key only). The original C1 audit called for 3/h per email and 5/h per IP to limit abuse and email bombing.
  • Context: Core reset flow is shipped ([[Projects/personal-finance-notion/backlog/done/p0-c1-password-reset|C1 done]]). This is hardening, not a missing feature.

Acceptance criteria

  • [ ] Dedicated limiter(s) or key namespace: password-reset:email:<addr> โ†’ max 3 / hour
  • [ ] IP dimension: derive client IP from headers in the server action (or shared helper used by other auth flows); key password-reset:ip:<ip> โ†’ max 5 / hour
  • [ ] When either limit trips, requestPasswordReset still returns { success: true } (no enumeration leak)
  • [ ] Unit or integration test for limit behavior (optional but preferred)

Implications

If skipped

  • Attackers can trigger high-volume reset emails to a victim address (harassment) or burn Resend quota. Enumeration remains fixed; abuse and cost risk remain.

Why this priority

  • p1 โ€” abuse and email-bombing risk after happy-path reset works; not p0 because recovery flow is already shippable.

When shipped

  • Reset requests align with audit abuse model; complements enumeration-safe responses from C1.

Dependencies

  • None. Shares RateLimitModel / rateLimiter.ts with login/signup limiters.

Links

  • App repo: src/lib/actions/passwordReset.ts, src/lib/utils/rateLimiter.ts