Affected versions
Symfony Security HTTP versions <5.4.56, >=6, <6.4.50, >=7, <7.4.23, >=8, <8.1.11 are affected by this security issue.
The issue has been fixed in Symfony Security HTTP 5.4.56, 6.4.50, 7.4.23, 8.1.11.
Description
Security::login() and UserAuthenticatorInterface::authenticateUser() log a user in programmatically, for example after a password reset or after an email verification link. The fix for CVE-2024-50341 made Security::login() call the checkPreAuth() method of the user checker of the firewall. But neither method ran checkPostAuth(): this method runs on the security.authentication.success event, which AuthenticatorManager::authenticateUser() did not dispatch.
As a consequence, an account that a user checker rejects in checkPostAuth(), such as an expired account, was refused by form login and the other authenticators of the firewall, but could still be logged in through these methods.
Applications are affected when they use a custom user checker that rejects users in checkPostAuth() and log users in programmatically. The default user checker does nothing in checkPostAuth().
Resolution
AuthenticatorManager::authenticateUser() now dispatches the security.authentication.success event once the token is created and before it is stored, as authentications through the firewall do. checkPostAuth() runs on this event and can reject the user.
As a consequence, an exception thrown by checkPostAuth() now comes out of Security::login() and authenticateUser(). Code that logs users in programmatically, such as a registration controller, may need to catch it.
The patches for this issue are available here for branch 5.4 (and forward-ported to 6.4, 7.4, 8.1 and 8.2).
Credits
We would like to thank Vincent Cassiau (CyberVanguard) for reporting the issue and Nicolas Grekas for providing the fix.