feat(security): Implement sliding-window rate limiting on auth endpoint to prevent brute-force attacks#402
Merged
Aditya948351 merged 3 commits intoMay 31, 2026
Conversation
Aditya948351
approved these changes
May 31, 2026
Collaborator
|
Do star the repo and thanks for the Contribution! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat(security): Implement sliding-window rate limiting on auth endpoint to prevent brute-force attacks #360
Summary
The
/api/auth/verify-adminroute accepted unlimited POST requests with no throttling,allowing an attacker to brute-force the admin key by hammering the endpoint programmatically.
This PR introduces a zero-dependency, in-memory sliding-window rate limiter built natively
for Next.js Route Handlers, capped at 5 attempts per IP per 60 seconds on the
admin key verification endpoint.
Problem
With no throttle in place, a script could submit thousands of guesses per second.
The admin key space — while secret — should never rely solely on key secrecy as
the only line of defence. Each failed attempt also triggered an unnecessary Firestore
read, meaning a sustained attack would simultaneously inflate database read costs.
Solution
Architecture: Sliding Window vs Fixed Window
A fixed-window limiter (e.g. "10 requests per minute, reset at :00") has a known
bypass: an attacker can fire 10 requests at 0:59 and 10 more at 1:01, achieving
20 requests in 2 seconds while staying within the per-minute limit.
The sliding window eliminates this by measuring the last N milliseconds from now,
not from a fixed clock boundary. Every request checks whether the oldest timestamp
in the window has aged out, and the window slides continuously.
New Files
src/lib/rateLimiter.tsDesign decisions:
Mapstorex-real-ip→cf-connecting-ip→x-forwarded-forcovers Vercel, Cloudflare, and standard reverse proxiesRetry-AfterheaderX-RateLimit-*headersnpm installrequired — no supply-chain surface addedModified Files
src/app/api/auth/verify-admin/route.tsWhy 5 attempts per 60 seconds?
The admin key is a high-value secret. 5 attempts per minute is generous enough for
a legitimate admin who misremembers their key, while making automated brute-force
infeasible — at 5 req/min, exhausting a 10-character alphanumeric keyspace would
take longer than the age of the universe.
Firestore is also only queried after the rate check passes, so blocked requests
cost zero database reads.
Reusability
The
rateLimitutility is fully generic and can protect any future Route Handlerwith a single line:
Security Impact
Retry-After,X-RateLimit-Remaining,X-RateLimit-ResetreturnedVerification
/api/auth/verify-adminwith an incorrect key in quick succession — all return401.429with body{ success: false, message: "Too many key attempts..." }and headersRetry-After,X-RateLimit-Limit: 5,X-RateLimit-Remaining: 0.Retry-Afterduration and retry — request is accepted again.{ success: true }as expected.Branch
fix/auth-rate-limiting→master