Bug Description
All rate limiters in backend/middlewares/rateLimiter.js (authLimiter, aiLimiter, generalLimiter, sensitiveAuthLimiter) are constructed without a store option, so express-rate-limit falls back to its default in-memory MemoryStore. Combined with app.set("trust proxy", 1) in server.js — indicating the app is built for a proxied cloud deployment (Render) — this means rate-limit counters do not survive process restarts and are not shared across multiple instances.
Steps to Reproduce
- Deploy (or simulate) two instances/processes of the backend behind a load balancer or reverse proxy.
- From a single client IP, send requests to an endpoint guarded by authLimiter or aiLimiter, distributing them across both instances.
- Compare the total number of successful requests to the configured
max.
Expected Behavior
Rate limits (e.g. 50 login attempts / 15 min, 20 AI requests / hour) should be enforced cumulatively per client regardless of which backend instance handles the request, and should persist correctly across restarts/deploys.
Actual Behavior
Each instance maintains its own independent in-memory counter, so a client can receive roughly max * number_of_instances requests through in a single window, and any restart or deploy resets all counters to zero — silently weakening brute-force protection on auth endpoints and cost controls on paid AI/LaTeX API calls.
Severity
High
Screenshots / Screen Recording
No response
Browser
No response
Operating System
No response
Additional Context
No response
Bug Description
All rate limiters in backend/middlewares/rateLimiter.js (authLimiter, aiLimiter, generalLimiter, sensitiveAuthLimiter) are constructed without a
storeoption, so express-rate-limit falls back to its default in-memory MemoryStore. Combined withapp.set("trust proxy", 1)in server.js — indicating the app is built for a proxied cloud deployment (Render) — this means rate-limit counters do not survive process restarts and are not shared across multiple instances.Steps to Reproduce
max.Expected Behavior
Rate limits (e.g. 50 login attempts / 15 min, 20 AI requests / hour) should be enforced cumulatively per client regardless of which backend instance handles the request, and should persist correctly across restarts/deploys.
Actual Behavior
Each instance maintains its own independent in-memory counter, so a client can receive roughly
max * number_of_instancesrequests through in a single window, and any restart or deploy resets all counters to zero — silently weakening brute-force protection on auth endpoints and cost controls on paid AI/LaTeX API calls.Severity
High
Screenshots / Screen Recording
No response
Browser
No response
Operating System
No response
Additional Context
No response