Skip to content

fix(auth): rate-limit OTP email sending#260

Open
ttonyxx wants to merge 1 commit into
security/03-ics-ssrf-guardfrom
security/04-otp-send-rate-limit
Open

fix(auth): rate-limit OTP email sending#260
ttonyxx wants to merge 1 commit into
security/03-ics-ssrf-guardfrom
security/04-otp-send-rate-limit

Conversation

@ttonyxx

@ttonyxx ttonyxx commented May 29, 2026

Copy link
Copy Markdown
Collaborator

Severity: 🟡 Medium — email bombing / abuse via unauthenticated endpoint

Stacked on #259 (→ #258#257).

The problem

/auth/otp/send is unauthenticated and emits a fresh OTP email on every request, with no throttling. Since the target email is fully attacker-controlled, anyone can:

  • bomb any inbox with OTP emails by replaying the request, and
  • run up email-provider cost / probe the system.

The verify endpoint caps guesses at 5/code, but nothing limited requesting codes.

The fix

  • Add CreatedAt to OtpCode.
  • sendOtp refuses to issue a new code if one was sent to that email within a 30-second cooldown, returning 429 otp-rate-limited.

Backward compatible: pre-existing codes without createdAt decode to the zero time and fall outside the cooldown. The per-code 5-attempt verification cap is unchanged.

🤖 Generated with Claude Code

## Why this change is needed

`/auth/otp/send` generated and emailed a fresh OTP on every request with no
throttling. An attacker could:

- bomb any victim's inbox by repeatedly POSTing their email (the address is
  fully attacker-controlled and the endpoint is unauthenticated), and
- cheaply probe the system / drive up email-provider cost.

The verify endpoint already caps guesses at 5 attempts per code, but nothing
limited how often a new code could be requested.

## What this does

- Adds a `CreatedAt` timestamp to `OtpCode`.
- `sendOtp` now refuses to issue a new code if one was already sent to that
  email within a 30-second cooldown, returning `429 otp-rate-limited`.

This is backward compatible: existing codes without `createdAt` decode to the
zero time and are simply treated as outside the cooldown. The per-code
5-attempt verification cap is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ttonyxx ttonyxx force-pushed the security/03-ics-ssrf-guard branch from c5364ea to 62df3e5 Compare May 29, 2026 18:49
@ttonyxx ttonyxx force-pushed the security/04-otp-send-rate-limit branch from 5a50270 to 0bc149f Compare May 29, 2026 18:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant