Harden email verification resend against abuse

Add a per-address confirmation-email cooldown and disable the
resend/forgot-password submit buttons while the mutation is in
flight so callers cannot flood the mail queue or double-submit.

Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
Émile Ré
2026-07-28 10:35:12 +02:00
parent 5d0882778f
commit 82a62005f8
5 changed files with 66 additions and 12 deletions

View File

@@ -76,6 +76,11 @@ var SupportedIdentityLocales = []string{
const (
TokenTypeEmailConfirmation = "email_confirmation"
// emailConfirmationResendCooldown is the minimum time between confirmation
// emails for the same address. Resend requests inside this window succeed
// without enqueueing another message (anti-enumeration + anti-abuse).
emailConfirmationResendCooldown = time.Minute
)
func NewAccountService(svc *Service) *AccountService {
@@ -243,6 +248,20 @@ func (s AccountService) ResendVerificationEmail(ctx context.Context, email mail.
return nil // Don't leak information about already-verified identities
}
recent, err := coredata.ExistsByRecipientSubjectCreatedAfter(
ctx,
tx,
identity.EmailAddress,
emails.SubjectConfirmEmail,
time.Now().Add(-emailConfirmationResendCooldown),
)
if err != nil {
return fmt.Errorf("cannot check recent confirmation email: %w", err)
}
if recent {
return nil // Cooldown: avoid flooding the recipient / mail queue
}
confirmationToken, err := statelesstoken.NewToken(
s.tokenSecret,
TokenTypeEmailConfirmation,