Skip to content

fix(backend): rate limiter admits the Nth request itself (off-by-one) - #2033

Open
masyarakatai wants to merge 1 commit into
LabsCrypt:mainfrom
masyarakatai:fix/rate-limit-off-by-one
Open

masyarakatai wants to merge 1 commit into
LabsCrypt:mainfrom
masyarakatai:fix/rate-limit-off-by-one

Conversation

@masyarakatai

Copy link
Copy Markdown

Closes #2027.

Root cause: INCR_AND_EXPIRE_SCRIPT increments before returning currentCount, so when maxRequests is 5, the 5th request already reads currentCount: 5 — and 5 < 5 rejected it. Every limiter on checkRateLimit therefore allowed maxRequests - 1 per window.

Fix: one operator — currentCount <= config.maxRequests in backend/src/services/rateLimitService.ts (checkRateLimit), with a short comment explaining why <= is the honest boundary for this script.

Tests (updated to pin the boundary the issue describes):

  • The old fixture asserted the buggy behaviour ([5, ...] → not allowed, and the concurrent test expecting 4 allowed). Now: currentCount === maxRequests is admitted with remaining: 0, and one past the limit (6) is blocked.
  • The concurrent-replay test now asserts exactly 5 admitted / 5 blocked out of 10 against a limit of 5.

Verification: service suite 9/9, middleware suite 10/10, typecheck clean, lint clean of errors (39 pre-existing warnings untouched).

The counter script increments before returning, so the maxRequests-th
request comes back with currentCount === maxRequests. '<' rejected it
even though it was still inside the window; '<=' fixes the off-by-one
described in LabsCrypt#2027.

Tests updated to pin the window boundary: the Nth request is admitted,
the N+1-th is blocked, and a concurrent burst admits exactly
maxRequests.

This branch has not been deployed

No deployments
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.

[Bug][Backend] rateLimitService.checkRateLimit uses '<' instead of '<=' causing off-by-one that blocks the Nth allowed request

1 participant