Skip to content

feat: implement memory-bounded bucket eviction for rate limiter and a… - #232

Open
GiftedGiftB wants to merge 1 commit into
AnchorNet-Org:mainfrom
GiftedGiftB:The-rate-limiter-keeps-buckets-in-a-process-local
Open

feat: implement memory-bounded bucket eviction for rate limiter and a…#232
GiftedGiftB wants to merge 1 commit into
AnchorNet-Org:mainfrom
GiftedGiftB:The-rate-limiter-keeps-buckets-in-a-process-local

Conversation

@GiftedGiftB

Copy link
Copy Markdown

Closed #223

Description

This PR addresses the high-priority vulnerability regarding the rateLimiter middleware, specifically mitigating the unbounded memory growth (memory-pressure vector) while formalizing the operational behavior for multi-instance deployments.

1. Store Decision (Explicit Deferral)

After evaluation, I have deliberately deferred the introduction of a shared distributed store (like Redis) for rate limiting. This service currently has no external storage dependencies and no persistence layer. Introducing one strictly for rate limiting would prematurely bloat the operational footprint of the service. This explicit deferral is now documented in README.md, and it will be revisited when the broader persistence layer issue is resolved.

2. Fail-Open / Fail-Closed Reasoning

Because the shared store decision has been deferred and rate limiting remains completely in-memory, network failure policies regarding a cache store are not applicable at this stage. The limiter operates entirely locally within the Node.js process and does not suffer from external store outages.

3. Read-Path Conclusion

We are continuing to leave standard GET reads unlimited. The only computationally expensive "read" operation (POST /api/v1/quote) is already independently bounded by its own stricter rate limiter instance in src/app.ts. Standard stateless GET requests are extremely fast and do not mutate state, so leaving them unlimited is acceptable for now.

4. Memory Bounds Implementation (Fixing Unbounded Growth)

To defend against the memory-pressure attack vector, a hard capacity limit (MAX_BUCKETS = 5000) has been added to the local Map state. If an attacker cycles distinct IPs, the limiter will:

  • Lazily prune expired buckets when capacity is reached.
  • Safely evict the oldest entry if the capacity remains full.

Verification

The following tests were successfully added and pass with no external dependencies:

  • Bypass Test: Explicitly demonstrates that multi-instance deployments without a shared store grant clients a full quota per instance.
  • Bounded-Growth Test: Proves that the bucket state remains strictly bounded (capping at 5000) under a flood of distinct IP keys by evicting the oldest entries.
  • The standard npm run lint, npm run build, and npm test suites pass fully with 0 regressions, preserving default limits and windows.

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.

The rate limiter keeps buckets in a process-local Map, so limits multiply by replica count and reset on every deploy

1 participant