Rate Limiter Free-for-All — JavaScript Bug Hunt
The public API of Relay Notify is supposed to allow 3 requests per 10 seconds per client.
- Language: JavaScript
- Layer: Backend
- Difficulty: Hard
- Modelled on: Public API platforms
- Visible tests: the first three requests pass; the fourth request inside the window is throttled; clients are limited independently
- Reward: 50 XP for a complete fix
Briefing
The public API of Relay Notify is supposed to allow 3 requests per 10 seconds per client. Under load testing, one client got 40 requests through — and separate clients are mysteriously throttling each other.
The clock and the app wiring are locked. The sliding-window logic in rateLimiter.js has (at least) two independent bugs.
Bug report
BUG-7010 · Priority: Critical · Reported by: SRE
Observed with limit=3, windowMs=10000:
- client A fires 5 requests instantly -> ALL 5 allowed (expected 3)
- client A then gets blocked... and so does client B, who sent nothing
- after waiting 10+ seconds, clients stay blocked longer than they should
Contract: allow(clientId, nowMs) -> true/false.
Logs
[limit] allow A t=0 -> true
[limit] allow A t=1 -> true
[limit] allow A t=2 -> true
[limit] allow A t=3 -> true <- should be false
[limit] allow B t=4 -> false <- B never sent anything before!The code as shipped
src/mw/rateLimiter.js (editable)
// Sliding-window rate limiter: LIMIT requests per WINDOW_MS per client.
var LIMIT = 3;
var WINDOW_MS = 10000;
var hits = [];
exports.allow = function (clientId, nowMs) {
// Drop hits that have left the window
hits = hits.filter(function (h) {
return h.at > nowMs - WINDOW_MS && h.at !== nowMs - WINDOW_MS;
});
hits.push({ client: clientId, at: nowMs });
var count = 0;
for (var i = 0; i < hits.length; i++) {
count++;
}
return count <= LIMIT + 1;
};
exports.resetAll = function () {
hits = [];
};
Read-only context: src/mw/app.js.
Open the hunt to edit the files, run the visible tests and submit against the hidden ones. More JavaScript bug hunts.