Skip to content

Key rate limiter on client IP and add verifiedTokens cleanup#2157

Merged
felladrin merged 4 commits into
mainfrom
rate-limit-by-ip-2126
Jul 22, 2026
Merged

Key rate limiter on client IP and add verifiedTokens cleanup#2157
felladrin merged 4 commits into
mainfrom
rate-limit-by-ip-2126

Conversation

@felladrin

Copy link
Copy Markdown
Owner

Summary

Fixes #2126. The rate limiter was keyed on a client-rotatable argon2 hash — each request generated a fresh hash with a new random salt, so the rate limiter never actually limited. The verifiedTokens Set also grew unbounded with no cleanup.

Changes

  • server/verifyTokenAndRateLimit.ts: Added getClientIp() to extract the real client IP from the rightmost X-Forwarded-For entry (the one our proxy appended), X-Real-IP, or socket.remoteAddress. Rate limiter now keyed on IP instead of token. IPs validated with net.isIP() to prevent unbounded key injection.
  • server/verifiedTokens.ts: Added periodic cleanup every 60s to prevent unbounded Set growth.
  • server/handleTokenVerification.ts: Added optional IncomingMessage parameter, passes it through to verifyTokenAndRateLimit.
  • server/searchEndpointServerHook.ts & server/internalApiEndpointServerHook.ts: Pass request to handleTokenVerification.

Verification

  • npm run lint passes clean
  • All 23 tests pass, including new tests for IP extraction, spoofing rejection, and array-valued headers

Note

Users behind the same IP will now share a rate-limit bucket (10 req/10s).

@felladrin felladrin changed the title GNX-2126: Key rate limiter on client IP and add verifiedTokens cleanup Key rate limiter on client IP and add verifiedTokens cleanup Jul 21, 2026
@felladrin
felladrin marked this pull request as ready for review July 22, 2026 20:38
- Key the rate limiter on client IP (from X-Forwarded-For rightmost
  entry, X-Real-IP, or socket.remoteAddress) instead of the client-
  rotatable argon2 hash, which allowed bypassing the limit by rotating
  the token each request
- Validate extracted IPs with net.isIP() to prevent unbounded key
  injection from malformed headers
- Add periodic cleanup (every 60s) to verifiedTokens Set to prevent
  unbounded memory growth
- Pass IncomingMessage through handleTokenVerification to both server
  hooks so the IP can be extracted

Note: users behind the same IP will now share a rate-limit bucket.
@felladrin
felladrin force-pushed the rate-limit-by-ip-2126 branch from 3e04761 to 5a0057b Compare July 22, 2026 20:38
@felladrin
felladrin merged commit e8f50ed into main Jul 22, 2026
2 checks passed
@felladrin
felladrin deleted the rate-limit-by-ip-2126 branch July 22, 2026 20:48
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.

Rate limiter is keyed on a client-rotatable token, and verifiedTokens grows unbounded

1 participant