- Shipped
- August 28, 2026 at 3:17 AM UTC
- Author
- Kamo
- Commit
- af05296
The endpoint had no limit of any kind. The *** the register screen demanded before enabling its resend button was never read here — the request body is three fields of JSON and nothing on the server looked for a payload — so the control gated a button, not the request, and a script posting straight at this URL was already unlimited. VerificationResendRateLimiter replaces it with a budget the server owns: a 60s cooldown taken as a single SET NX so racing replicas cannot both win, 5/hour and 15/day per address, and 20/hour per public IP. Checked BEFORE the org and user lookup and keyed on the SUBMITTED address, so a probe costs budget whether or not the account exists and the 429 does not become the account-existence oracle that the endpoint's careful "if this account exists" answer exists to avoid. The IP window is skipped for a non-public address: undetermined must not collapse into one shared key for every registrant. Redis-backed because this service runs replicas, and fails open on a Redis outage. A rejection answers 429 with Retry-After and retryAfterSeconds, so the screen can count down against this clock rather than guess at its own.