Skip to content

Replace in-process Map-based rate limiter with a Redis ZSET sliding-window #212

Closed

Description

@kilodesodiq-arch

Problem Statement. createRateLimiter() in app/backend/src/common/security/security.module.ts
uses a process-locale Map<string, {count, resetTimeMs}> as its store. At scale, this
(a) wastes memory proportional to unique client IPs, (b) silently loses the limit counter when
the process restarts (an attacker simply widens their budget across restarts), (c) does not
share state across the many replicas one would deploy behind a load balancer.

Why it matters. Rate limiting is one of the cheapest, broadest defenses. A loss-of-state
or per-replica division of the limit is the difference between effective DoS mitigation and
incidental throttling.

Technical Context. The repo already imports both @liaoliaots/nestjs-redis and
@nestjs/throttler. The throttler module is configured with a global 20 req/min limit in
app.module.ts. The current createRateLimiter is registered as an Express middleware via
app.use(createRateLimiter(cs)) in main.ts. The store needs to be migrated.

Expected Outcome. A sliding-window limiter using a Redis sorted set, with all current
behaviour preserved (headers, exempt paths, isVerificationPath special case) and configurable
window/limit via env.

Acceptance Criteria.

  • New RedisSlidingWindowRateLimiter middleware with the same interface
    ((req, res, next) => void).
  • Configurable via RATE_LIMIT_WINDOW_MS and RATE_LIMIT_LIMIT envs.
  • A new e2e test asserts: 100 hits in 1 s => 80+ return 429, headers include
    RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset, Retry-After.
  • A redis-down test (use ioredis-mock) asserts the limiter fails open with a WARN log,
    not 500.

Implementation Notes. Replace the Map store with a ZADD/ZCOUNT/ZREMRANGEBYSCORE
per key; reuse the req.ips[0] fallback for the key. Use MULTI to keep header reads
consistent.

Files or modules likely to be affected. src/common/security/security.module.ts,
src/common/guards/adaptive-rate-limit.guard.ts, app/backend/test/security.e2e-spec.ts,
app.module.ts (registration order).

Dependencies. None (but mutually exclusive with the throttler guard in #46).

Difficulty. Hard
Estimated effort. M



Backlog item #4 from `docs/maintainer-issue-backlog.md.

Activity

  1. AugistineCreates commented on Jul 15, 2026

    @AugistineCreates
    Contributor

    Please assign this issue to me my eta is 4 hours

  2. grantfox-oss commented on Jul 15, 2026

    @grantfox-oss

    🦊 GrantFox — @AugistineCreates has been assigned to this issue as part of the Official Campaign | FWC26 campaign!

    Next steps:

    1. Open a Pull Request referencing this issue (e.g., Closes #212)
    2. Your PR will be reviewed by the ChainForgee maintainers

    Good luck! Track your progress on GrantFox.

  3. grantfox-oss commented on Jul 19, 2026

    @grantfox-oss

    🎉 This issue has been marked as completed on GrantFox as part of the Official Campaign | FWC26 campaign!

    @AugistineCreates's PR #343 was approved and merged by @kilodesodiq-arch.

    🏆 @AugistineCreates: You earned 45 FoxPoints for this contribution! Your current tier: Specialist (3,124 total points). Track your full progress on GrantFox.

    👏 Great work, @AugistineCreates! Keep contributing to ChainForgee.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions