Files
plm-lottery/app
davideandClaude Opus 5 ab65728bdc Bound the rate limiter's bucket dict (B-56)
_buckets is keyed by strings the caller chooses — any username, and (before
B-54) any IP — and only ever grew: decay_seconds aged a bucket's counter but
never removed the entry, so hammering login with random usernames was an
unbounded memory leak.

A bucket is "spent" once its lockout has expired *and* its failure count would
decay to zero on the next failure anyway — at which point keeping it and
dropping it are indistinguishable, which is what makes eviction safe. Those are
swept on record_failure (at most once every 60s) and on the read path, so a key
that's merely being probed never leaves an entry behind. That alone holds the
dict at the size of the genuinely active attack surface.

_MAX_BUCKETS = 50_000 is the backstop for a burst faster than the sweep
interval, when nothing has had time to expire. Over it, the entries closest to
expiry go first: what an attacker gets from a successful flood is the loss of
the shallowest, nearly-over lockouts, never the deep ones actually holding an
attack back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 22:22:51 +02:00
..
2026-07-21 10:26:31 +02:00