craftcms/cms: Verification code survives verify-email use and remains valid for set-password
What fixes it
- 5.11.0craftcms/cms, composerGitHub
composer require "craftcms/cms:^5.11.0"
A fixed version on one release line is not the upgrade target for every line. Check your exact version and any vendor backports.
Description
Craft’s user verification code is a single secret that authorizes two distinct unauthenticated actions — users/verify-email and users/set-password — but only one of those consumption paths invalidates it.
Users::verifyEmailForUser() (src/services/Users.php:982-1010, 5.10.13.2) clears verificationCode only for "pending" users, via activateUser() (:1004-1006). For an already active user who is changing their email address, the function promotes unverifiedEmail to email and returns without clearing the code.
The same code is then accepted a second time by users/set-password, which performs a full password reset. set-password itself correctly nulls the code on use (src/elements/User.php:2655) — only the verify-email path leaks the second use.
Net effect: one emailed code yields two independent account-recovery actions instead of one, and the victim’s own legitimate use of the code (verifying the new address) does not consume it.
Impact
An attacker who possesses a victim’s verification code — e.g., observed or leaked from a mailbox, shared inbox, or logs — and who lets (or tricks) the victim into completing the email-change verification can afterward reset the victim’s password with the same code and log in, after the victim reasonably believes the code was consumed. Honest precondition: the attacker must obtain the code out of band, and the flow starts with an email change to an active account.
Report ID: 1683
Text from GitHub Advisory Database
Affected versions 1
- craftcms/cms, composer>= 5.0.0, < 5.11.0GitHub