fix: add memory protection to lookup rate limiting

ENUM-002: Lookup rate limit now respects LOOKUP_RATE_LIMIT_MAX_ENTRIES
(default 10000) to prevent memory exhaustion from unique IP flood.

Eviction strategy: expired entries first, then oldest by last request.
This commit is contained in:
Username
2025-12-26 00:16:41 +01:00
parent 0fa6052f69
commit 4f5da8ca66
2 changed files with 26 additions and 0 deletions

View File

@@ -339,11 +339,33 @@ def check_lookup_rate_limit(client_ip: str) -> tuple[bool, int]:
window = current_app.config.get("LOOKUP_RATE_LIMIT_WINDOW", 60)
max_requests = current_app.config.get("LOOKUP_RATE_LIMIT_MAX", 60)
max_entries = current_app.config.get("LOOKUP_RATE_LIMIT_MAX_ENTRIES", 10000)
now = time.time()
cutoff = now - window
with _lookup_rate_limit_lock:
# ENUM-002: Memory protection - prune if at capacity
if len(_lookup_rate_limit_requests) >= max_entries:
if client_ip not in _lookup_rate_limit_requests:
# Evict expired entries first
expired = [
ip
for ip, reqs in _lookup_rate_limit_requests.items()
if not reqs or reqs[-1] <= cutoff
]
for ip in expired:
del _lookup_rate_limit_requests[ip]
# If still at capacity, evict oldest entries
if len(_lookup_rate_limit_requests) >= max_entries:
sorted_ips = sorted(
_lookup_rate_limit_requests.items(),
key=lambda x: x[1][-1] if x[1] else 0,
)
for ip, _ in sorted_ips[: max_entries // 4]:
del _lookup_rate_limit_requests[ip]
requests = _lookup_rate_limit_requests[client_ip]
requests[:] = [t for t in requests if t > cutoff]