Skip to content

fix(auth): bound email verification attempts and randomize links - #1

Closed
Gugic wants to merge 2 commits into
inworld/v2.197.0from
codex/gotrue-verification-hardening
Closed

Gugic wants to merge 2 commits into
inworld/v2.197.0from
codex/gotrue-verification-hardening

Conversation

@Gugic

@Gugic Gugic commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Email-link credentials currently inherit the numeric OTP guessing space, and failed code guesses have no shared account budget. This separates the credentials and enforces verification limits in GoTrue.

Prerequisite: merge #2 first, then refresh this branch from inworld/v2.197.0. Both PRs target the maintained branch independently. A temporary combined tree is conflict-free and passes the H1 security and shared-attempt suites under Go 1.27.2 and the upgraded dependencies.

  • Generate independent 256-bit email-link credentials and store numeric-code hashes separately. Preserve GET links, POST token_hash/code forms, PKCE, email-hook mailbox mapping and admin-generated links.
  • Admit at most 10 failed or in-flight code attempts per normalized email and JWT audience in 15 minutes by default, across replicas, IPs, verification types and replacement codes. Successful requests and non-credential errors refund reservations; database failures remain conservative until the window expires. Email-link redemption remains available after code-budget exhaustion.
  • Lock challenge consumption so concurrent code/link redemption issues at most one session. Add two additive migrations, bounded expiry cleanup, configuration documentation and regression coverage.

The recovery-code functional suite uses a bounded test-only two-minute request deadline: Argon2 under race/coverage exceeded the production ten-second deadline while testing lockout state transitions.

Targets the maintained inworld/v2.197.0 branch as explicitly requested. This PR changes source only. Rollout needs a new fork tag/image and separate deployment PRs. Existing credentials retain their original expiry. During a mixed-version rollout or rollback, older binaries can redeem the new links but cannot redeem newly issued numeric codes. Full containment requires all replicas updated and legacy low-entropy links expired.

Verified:

  • Full make test passed with Go 1.27.0, race detection, repository-wide coverage and the required coverage gate, including all six new security regression tests.
  • Go 1.27.0: formatting, vet, staticcheck and gosec passed.
  • Reproduced missing attempt limits, deterministic link credentials and 32 concurrent sessions before the fixes.
  • This standalone head's make lint reports 13 vulnerabilities also reproduced on its unchanged base. The separate prerequisite PR fix(deps): patch Go dependencies and restore fork CI #2 clears them and the Go 1.27.2 Staticcheck compatibility issue.

Not verified:

  • GitHub CI and review, deployed email flows, and mixed-version deployment rehearsal. No image or deployment pins changed.

@Gugic
Gugic marked this pull request as ready for review October 20, 2026 19:38
@Gugic

Gugic commented Oct 20, 2026

Copy link
Copy Markdown
Owner Author

Moved to the organization-owned GHES fork: https://github.inworld.dev/inworld-ai/gotrue/pull/2. The refreshed e599e97 head passed all six GitHub.com checks after dependency PR #2 merged. Source history and this PR remain available for review context; continue review and merging on GHES.

@Gugic Gugic closed this Oct 20, 2026
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