Bound registrations with a per-IP quota instead of failure backoff (B-58)
The registration throttle called record_failure on every attempt, successful ones included. Five legitimate signups from one shared or NAT address locked the sixth real user out for up to 600s, doubling from there — while an attacker sidestepped the limiter entirely through B-54. Failure backoff is the wrong instrument here: nothing about creating an account is a failed guess at a secret, so the only people it reliably punished were the honest ones. RollingQuota says what was actually meant: 5 accounts per IP per hour, in a rolling window. The caller over it waits exactly until the oldest of the five ages out — an accurate Retry-After, and waiting never makes the next wait longer. It is recorded only once an account exists, so attempts that create nothing (a taken username, a validation error) leave the quota untouched, and checked before the Argon2 hash, so an IP out of quota costs nothing to refuse. Bounded like the failure limiter (B-56): the keys are caller-chosen, so the dict gets both a sweep and a hard cap, evicting keys with room left in their quota before full ones. Also fixes the inline comment that cited B-31 (the resubscribe finding) where it meant B-33. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
57721355f0
commit
0aac73e557
6 files changed
+183
-25
No files matched your search
@@ -40,20 +40,6 @@ remains the last prerequisite for running unattended.
|
||||
|
||||
## High — security
|
||||
|
||||
### B-58 — the registration throttle counts successes as failures and is IP-only
|
||||
|
||||
`app/auth/routes.py:66-71`.
|
||||
|
||||
`record_failure` is called on every registration attempt, successful ones
|
||||
included. Five legitimate signups from one shared/NAT address lock the sixth real
|
||||
user out with exponential backoff up to 600 s — while an attacker skips the limiter
|
||||
entirely through B-54. The intent (bounding accounts per source) is reasonable;
|
||||
the current shape punishes only honest users. The inline comment also cites B-31
|
||||
(the resubscribe finding) where it means B-33.
|
||||
|
||||
Fix: keep an accounts-per-IP quota if that is the goal, but express it as a quota
|
||||
rather than as failure backoff, and fix the B-nn reference.
|
||||
|
||||
### B-59 — deposit crediting is not corroborated, unlike external-spend detection
|
||||
|
||||
`app/deposits/service.py:31-45`, `app/electrum/listener.py:401-433`.
|
||||
|
||||
Reference in new issue
Block a user