Skip to content

fix(web): rate-limit and shorten lifetime of login OTP codes#1924

Open
richiemcilroy wants to merge 2 commits into
mainfrom
security/otp-bruteforce-protection
Open

fix(web): rate-limit and shorten lifetime of login OTP codes#1924
richiemcilroy wants to merge 2 commits into
mainfrom
security/otp-bruteforce-protection

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Jun 19, 2026

Copy link
Copy Markdown
Member

Shortens the email login OTP code validity to 15 minutes and adds per-email rate limiting on the verify and send endpoints, so the 6-digit code can no longer be brute-forced.

Greptile Summary

This PR hardens the email OTP login flow by shortening the verification-code lifetime from NextAuth's 24-hour default to 15 minutes, and wrapping the NextAuth catch-all route with per-email rate limiting backed by the Vercel Firewall, preventing both brute-force attacks and mailbombing.

  • packages/database/auth/auth-options.ts: adds maxAge: 15 * 60 to EmailProvider and corrects the dev-mode log message to match.
  • apps/web/lib/rate-limit.ts: introduces a new isRateLimited helper (production-only, fail-open) that centralises @vercel/firewall usage; RATE_LIMIT_IDS pre-declares rule strings for several planned future endpoints in addition to the two used here.
  • apps/web/app/api/auth/[...nextauth]/route.ts: wraps the handler with otpRateLimited, which gates /callback/email and /signin/email per-email (falling back to per-IP when the email is absent), using req.clone() to safely read the POST body without consuming the stream the NextAuth handler needs.

Confidence Score: 5/5

Safe to merge — the changes are additive security hardening with a well-documented fail-open fallback, and no existing functionality is altered.

All three changed files make narrow, well-scoped changes: the OTP lifetime reduction is a one-liner with no side effects, the new rate-limit helper faithfully mirrors the existing @vercel/firewall pattern already in production, and the route wrapper correctly clones the request body before forwarding to NextAuth.

No files require special attention.

Important Files Changed

Filename Overview
apps/web/app/api/auth/[...nextauth]/route.ts Wraps the NextAuth handler with per-email rate limiting for the OTP send and verify paths; uses endsWith for both paths (consistent), correctly clones the request before reading form data, and falls back to per-IP limiting when no email is present.
apps/web/lib/rate-limit.ts New utility wrapping @vercel/firewall's checkRateLimit; follows the fail-open, production-only pattern already established in the codebase. RATE_LIMIT_IDS centralises rule strings, though several IDs (LOOM_DOWNLOAD, TRANSLATE_TRANSCRIPT, etc.) are pre-declared for future endpoints and not yet wired up.
packages/database/auth/auth-options.ts Adds maxAge: 15 * 60 to EmailProvider to reduce OTP lifetime from the 24h NextAuth default to 15 minutes; updates the development console log to match.

Reviews (3): Last reviewed commit: "fix(web): refine OTP rate-limit key hand..." | Re-trigger Greptile

@polarityinc

polarityinc Bot commented Jun 19, 2026

Copy link
Copy Markdown

Paragon Review Skipped

Hi @richiemcilroy! Your Polarity credit balance is insufficient to complete this review.

Please visit https://app.paragon.run to finish your review.

@superagent-security

Copy link
Copy Markdown

Superagent didn't find any vulnerabilities or security issues in this PR.

Comment thread apps/web/app/api/auth/[...nextauth]/route.ts
@richiemcilroy

Copy link
Copy Markdown
Member Author

@greptileai please review the PR

Comment thread apps/web/app/api/auth/[...nextauth]/route.ts Outdated
Comment thread apps/web/app/api/auth/[...nextauth]/route.ts Outdated
Comment thread apps/web/app/api/auth/[...nextauth]/route.ts Outdated
Comment thread apps/web/app/api/auth/[...nextauth]/route.ts Outdated
@richiemcilroy

Copy link
Copy Markdown
Member Author

@greptileai please review the PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant