VerifyPreRegistrationEmailCommandHandler verifies a 6-digit email code by a direct local comparison (preReg.EmailVerificationCode == request.Code). It does preReg.EmailVerificationAttempts++ (line 64) and persists it, but never checks that counter against a maximum. So the code (10^6 possibilities) can be brute-forced within the pre-registration expiry window — the attempt counter exists but its enforcement was never added. There is no per-endpoint attempt cap; the code relies solely on any external rate-limiting.
Impact: an attacker who can reach the endpoint for a given PreRegistrationId could guess the code and mark an email verified without controlling it (registration/verification bypass).
The phone path is NOT affected — it uses the Twilio Verify API, which enforces attempt limits server-side.
Fix (this PR)
Enforce a max-attempts cap (5) in the email handler before validating: once EmailVerificationAttempts >= 5, reject with 'Too many verification attempts. Please request a new code.' The reset-on-resend already exists (ResendPreRegistrationCodesCommandHandler sets EmailVerificationAttempts = 0), so a legitimate user who mistypes recovers by requesting a new code — no usability regression. Added a unit test asserting that at the cap, even a correct code is rejected.
Note
Application-level attempt capping is defense-in-depth over network rate-limiting (which is per-IP and can be rotated); a short numeric code needs both.
## Vulnerability
`VerifyPreRegistrationEmailCommandHandler` verifies a **6-digit** email code by a direct local comparison (`preReg.EmailVerificationCode == request.Code`). It does `preReg.EmailVerificationAttempts++` (line 64) and persists it, but **never checks that counter against a maximum**. So the code (10^6 possibilities) can be brute-forced within the pre-registration expiry window — the attempt counter exists but its enforcement was never added. There is no per-endpoint attempt cap; the code relies solely on any external rate-limiting.
Impact: an attacker who can reach the endpoint for a given `PreRegistrationId` could guess the code and mark an email verified without controlling it (registration/verification bypass).
The phone path is NOT affected — it uses the Twilio Verify API, which enforces attempt limits server-side.
## Fix (this PR)
Enforce a max-attempts cap (5) in the email handler before validating: once `EmailVerificationAttempts >= 5`, reject with 'Too many verification attempts. Please request a new code.' The reset-on-resend already exists (`ResendPreRegistrationCodesCommandHandler` sets `EmailVerificationAttempts = 0`), so a legitimate user who mistypes recovers by requesting a new code — no usability regression. Added a unit test asserting that at the cap, even a correct code is rejected.
## Note
Application-level attempt capping is defense-in-depth over network rate-limiting (which is per-IP and can be rotated); a short numeric code needs both.
Resolved in spikersoft-backend PR #387 (merged to master). Enforced a 5-attempt cap on the 6-digit email verification code before validation (reset on resend); the code is no longer brute-forceable. Unit test added. Closing.
Resolved in spikersoft-backend PR #387 (merged to `master`). Enforced a 5-attempt cap on the 6-digit email verification code before validation (reset on resend); the code is no longer brute-forceable. Unit test added. Closing.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Vulnerability
VerifyPreRegistrationEmailCommandHandlerverifies a 6-digit email code by a direct local comparison (preReg.EmailVerificationCode == request.Code). It doespreReg.EmailVerificationAttempts++(line 64) and persists it, but never checks that counter against a maximum. So the code (10^6 possibilities) can be brute-forced within the pre-registration expiry window — the attempt counter exists but its enforcement was never added. There is no per-endpoint attempt cap; the code relies solely on any external rate-limiting.Impact: an attacker who can reach the endpoint for a given
PreRegistrationIdcould guess the code and mark an email verified without controlling it (registration/verification bypass).The phone path is NOT affected — it uses the Twilio Verify API, which enforces attempt limits server-side.
Fix (this PR)
Enforce a max-attempts cap (5) in the email handler before validating: once
EmailVerificationAttempts >= 5, reject with 'Too many verification attempts. Please request a new code.' The reset-on-resend already exists (ResendPreRegistrationCodesCommandHandlersetsEmailVerificationAttempts = 0), so a legitimate user who mistypes recovers by requesting a new code — no usability regression. Added a unit test asserting that at the cap, even a correct code is rejected.Note
Application-level attempt capping is defense-in-depth over network rate-limiting (which is per-IP and can be rotated); a short numeric code needs both.
Resolved in spikersoft-backend PR #387 (merged to
master). Enforced a 5-attempt cap on the 6-digit email verification code before validation (reset on resend); the code is no longer brute-forceable. Unit test added. Closing.