Skip to content

Add daily cap for email verifications#188

Merged
DJAndries merged 2 commits into
masterfrom
verify-cap
Jun 10, 2026
Merged

Add daily cap for email verifications#188
DJAndries merged 2 commits into
masterfrom
verify-cap

Conversation

@DJAndries

@DJAndries DJAndries commented May 15, 2026

Copy link
Copy Markdown
Collaborator

Resolves #183

@DJAndries DJAndries requested a review from fmarier May 15, 2026 22:15
Comment thread datastore/verifications.go Outdated
Comment thread util/error.go
ErrMaxCodeAttempts = NewExposedError(13010, "maximum code verification attempts exceeded")
ErrInvalidCode = NewExposedError(13011, "invalid verification code")
ErrRegistrationVerificationPending = NewExposedError(13012, "registration verification already pending for this email")
ErrDailyVerificationLimitReached = NewExposedError(13013, "daily verification limit reached for email")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @szilardszaloki New error code that we should also add to the client.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DJAndries Would you mind letting me know which endpoints can return this error condition? I know /v2/verify/init can. Perhaps /v2/accounts/password/init as well?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, both /v2/verify/init and /v2/accounts/password/init can return this error

Comment thread migrations/11_cron.up.sql

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to mitigate repeated brute-force email verification attempts by adding a per-email daily limit to verification initialization, and by retaining verification rows longer so the daily window can be enforced.

Changes:

  • Add a new exposed error for “daily verification limit reached”.
  • Enforce a per-email daily cap in Datastore.CreateVerification() by counting verifications created since start-of-day.
  • Extend the cron cleanup window for verifications and add controller/test coverage for the new error path.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
util/error.go Adds a new exposed error code for daily verification limiting.
migrations/11_cron.up.sql Extends verification-row retention to support daily counting.
datastore/verifications.go Adds daily-count logic to block further verification creation for an email.
controllers/verification.go Maps the new daily-cap error to a 400 response in /v2/verify/init.
controllers/verification_test.go Adds a test asserting daily-cap behavior on repeated /v2/verify/init calls.
Comments suppressed due to low confidence (1)

controllers/verification.go:155

  • ErrDailyVerificationLimitReached is now surfaced here as a 400, but InitializeVerification is also called from controllers/accounts.go (e.g. SetupPasswordInit when creating a registration verification). That path currently doesn’t treat this error as a client error, so it will respond 500 instead of 400 when the daily cap is hit. Consider adding the same error handling there (and any other call sites) to keep responses consistent.
	if err != nil {
		if errors.Is(err, util.ErrTooManyVerifications) ||
			errors.Is(err, util.ErrDailyVerificationLimitReached) ||
			errors.Is(err, util.ErrIntentNotAllowed) ||
			errors.Is(err, util.ErrEmailDomainNotSupported) ||
			errors.Is(err, util.ErrAccountExists) ||
			errors.Is(err, util.ErrRegistrationVerificationPending) ||
			errors.Is(err, util.ErrAccountDoesNotExist) {
			util.RenderErrorResponse(w, r, http.StatusBadRequest, err)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread datastore/verifications.go Outdated
Comment thread datastore/verifications.go Outdated
Comment thread datastore/verifications.go Outdated
Comment thread datastore/verifications.go Outdated
Comment thread migrations/11_cron.up.sql
Comment thread controllers/verification_test.go Outdated

@fmarier fmarier left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change the 5 for a 10 and then merge: https://github.com/brave/accounts/pull/188/files#r3277717457

@DJAndries DJAndries merged commit 08bda4a into master Jun 10, 2026
5 checks passed
@DJAndries DJAndries deleted the verify-cap branch June 10, 2026 18:34
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.

Add custom rate-limiter for verification code attempts

4 participants