Skip to content

[Devops]: express-rate-limit uses default in-memory store — limits are per-instance and reset on restart #376

Description

@Srejoye

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

  1. Deploy (or simulate) two instances/processes of the backend behind a load balancer or reverse proxy.
  2. From a single client IP, send requests to an endpoint guarded by authLimiter or aiLimiter, distributing them across both instances.
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions