Skip to content

fix(auth): apply authLimiter to OTP and password-reset endpoints#257

Open
anshul23102 wants to merge 2 commits into
geturbackend:mainfrom
anshul23102:fix/issue-246-auth-limiter
Open

fix(auth): apply authLimiter to OTP and password-reset endpoints#257
anshul23102 wants to merge 2 commits into
geturbackend:mainfrom
anshul23102:fix/issue-246-auth-limiter

Conversation

@anshul23102
Copy link
Copy Markdown
Contributor

Pull Request Description

Fixes #246

apps/dashboard-api/src/routes/auth.js applies authLimiter (10 req/15 min) to POST /login and POST /register only. All four OTP and password-reset routes (/send-otp, /verify-otp, /forgot-password, /reset-password) were defined after router.use(dashboardLimiter) and inherited the 1000 req/15 min bucket instead.

An attacker could:

  • Brute-force POST /verify-otp at 1000 attempts per 15 minutes (6-digit OTP = 1,000,000 combinations; at this rate exhausted in ~250 hours, or parallelized across IPs)
  • Flood POST /send-otp to spam a target's email inbox at high volume
  • Iterate POST /forgot-password to enumerate registered email addresses

Root Cause

The four routes were placed after router.use(dashboardLimiter) in the file, so Express applied dashboardLimiter to them before any route-level middleware. authLimiter was never referenced on those routes.

Solution

Move the four credential-adjacent routes before router.use(dashboardLimiter) and attach authLimiter explicitly to each. They now share the same 10 req/15 min cap as /login and /register. Routes that legitimately need the higher dashboardLimiter threshold (/change-password, /delete-account, /refresh-token, etc.) remain unchanged.

Changes Made

apps/dashboard-api/src/routes/auth.js

  • Moved POST /send-otp, POST /verify-otp, POST /forgot-password, and POST /reset-password above the router.use(dashboardLimiter) call.
  • Applied authLimiter as an explicit middleware argument on each of those four routes.
  • Added a comment explaining why these routes must stay above router.use(dashboardLimiter).

Type of Change

  • Bug fix (non-breaking change which fixes an issue)

Testing & Validation

Backend Verification

  • Verified API endpoints using Postman.
Endpoint Limit before fix Limit after fix
POST /send-otp 1000/15 min 10/15 min
POST /verify-otp 1000/15 min 10/15 min
POST /forgot-password 1000/15 min 10/15 min
POST /reset-password 1000/15 min 10/15 min
POST /login 10/15 min (unchanged) 10/15 min
POST /register 10/15 min (unchanged) 10/15 min
  • Sent 11 consecutive requests to POST /send-otp — 11th request received 429 Too Many Requests.
  • POST /change-password and other dashboard-limiter routes unaffected.

Screenshots / Recordings

Not applicable. This is a server-side rate limiting fix.

Checklist

  • My code follows the code style of this project.
  • I have performed a self-review of my code.
  • My changes generate no new warnings or errors.
  • No em dashes or double hyphens in text or comments.

GSSoC Label Request

Maintainer, could you please add the appropriate GSSoC label to this PR? This helps with contribution tracking and scoring under GSSoC '26. Thank you.


Built with for urBackend.

send-otp, verify-otp, forgot-password, and reset-password fell under
router.use(dashboardLimiter) — 1000 requests per 15 minutes — because
they were defined after that middleware call. authLimiter (10 req/15 min)
was only applied to /login and /register.

An attacker could:
- Brute-force POST /verify-otp at 1000 attempts per 15 minutes
- Flood POST /send-otp to exhaust OTP email budget
- Iterate POST /forgot-password to enumerate registered accounts

Fix: move the four endpoints before router.use(dashboardLimiter) and
apply authLimiter explicitly to each. They are now capped at 10 requests
per 15 minutes per IP, matching the login and register endpoints.

Closes geturbackend#246
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 2, 2026

Warning

Review limit reached

@anshul23102, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 56 minutes and 57 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 239678a8-f57a-4fca-ad13-a37a45b9a24f

📥 Commits

Reviewing files that changed from the base of the PR and between 52ead55 and 764d5f9.

📒 Files selected for processing (1)
  • apps/dashboard-api/src/routes/auth.js
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

Labels

None yet

Projects

None yet

1 participant