From 7d420111411255728ed51024f4c164d50e93d3ce Mon Sep 17 00:00:00 2001 From: JuliaEdom Date: Mon, 20 Jul 2026 15:01:55 +0300 Subject: [PATCH] docs(auth): record accepted risk on per-process failed-auth throttle (S-7) The failed-auth IP throttle is in-process while the request rate limiter is Redis-shared, so N replicas give an attacker N x the intended failed-auth budget. Accepted: API keys are 256-bit random values, brute force stays infeasible at any realistic replica count, and the throttle only needs to blunt log-flooding/scanning. Constraint comment documents when to revisit (key entropy drop, or alerting keying off this counter). Co-Authored-By: Claude Fable 5 --- src/serving/api/auth/manager.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/serving/api/auth/manager.py b/src/serving/api/auth/manager.py index 0bc8ea6..4171f17 100644 --- a/src/serving/api/auth/manager.py +++ b/src/serving/api/auth/manager.py @@ -440,6 +440,13 @@ async def charge_rate_limit(self, tenant_key: TenantKey, units: int) -> bool: return allowed def is_failed_auth_limited(self, client_ip: str) -> bool: + # Per-process on purpose (unlike the Redis-shared request rate limiter): + # on N replicas an attacker spreading guesses gets N x the failed-auth + # budget, which is an accepted risk while API keys are 256-bit random + # values — brute force is infeasible at any realistic multiple, and the + # throttle only has to blunt log-flooding/scanning. Revisit (move to + # Redis alongside `check_rate_limit`) if key entropy ever drops or + # failed-auth alerting starts keying off this counter. (audit S-7) now = self.time_source() cutoff = now - FAILED_AUTH_WINDOW_SECONDS window = [stamp for stamp in self._failed_auth_windows[client_ip] if stamp > cutoff]