CVE-2021-41268 (PHP, published 2021-11-24T19:15Z)
Description: value: Symfony/SecurityBundle is the security system for Symfony, a PHP framework for web and console applications and a set of reusable PHP components. Since the rework of the Remember me cookie in version 5.3.0, the cookie is not invalidated when the user changes their password. Attackers can therefore maintain their access to the account even if the password is changed as long as they have had the chance to login once and get a valid remember me cookie. Starting with version 5.3.12, Symfony makes the password part of the signature by default. In that way, when the password changes, then the cookie is not valid anymore.
Severity: MEDIUM (CVSS v3 base score: 8.8)
Weakness: CWE-384 \u2014 Session Fixation
Authenticating a user, or otherwise establishing a new user session, without invalidating any existing session identifier gives an attacker the opportunity to steal authenticated sessions.
Repository: https://github.com/symfony/symfony
Files changed:
src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/RememberMeBundle/Security/UserChangingUserProvider.php
src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeTest.php
Commit message: [SecurityBundle] Default signature_properties to the previous behavior


Vulnerable code:
        return $this->inner->loadUserByUsername($username);
        return $this->inner->loadUserByIdentifier($userIdentifier);
        $user = $this->inner->refreshUser($user);

        $alterUser = \Closure::bind(function (InMemoryUser $user) { $user->password = 'foo'; }, null, class_exists(User::class) ? User::class : InMemoryUser::class);
        $alterUser($user);

        return $user;
        $this->assertNotNull($cookieJar->get('REMEMBERME'));
        $this->assertNotNull($cookieJar->get('REMEMBERME'));

Fixed code:
                ->defaultValue(['password'])
    public static $changePassword = false;

        return $this->changeUser($this->inner->loadUserByUsername($username));
        return $this->changeUser($this->inner->loadUserByIdentifier($userIdentifier));
        return $this->changeUser($this->inner->refreshUser($user));

    private function changeUser(UserInterface $user): UserInterface
    {
        if (self::$changePassword) {
            $alterUser = \Closure::bind(function (InMemoryUser $user) { $user->password = 'changed!'; }, null, class_exists(User::class) ? User::class : InMemoryUser::class);
            $alterUser($user);
        }

        return $user;
    }
use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\RememberMeBundle\Security\UserChangingUserProvider;

    protected function setUp(): void
    {
        UserChangingUserProvider::$changePassword = false;
    }

        $this->assertNotNull($cookie = $cookieJar->get('REMEMBERME'));

        UserChangingUserProvider::$changePassword = true;
        // change password (through user provider), this deauthenticates the session

        // restore the old remember me cookie, it should no longer be valid
        $cookieJar->set($cookie);
        $client->request('GET', '/profile');
        $this->assertRedirect($client->getResponse(), '/login');
        $this->assertNotNull($cookie = $cookieJar->get('REMEMBERME'));

        UserChangingUserProvider::$changePassword = true;
        // change password (through user provider), this deauthenticates the session

        // restore the old remember me cookie, it should no longer be valid
        $cookieJar->set($cookie);
        $client->request('GET', '/profile');
        $this->assertRedirect($client->getResponse(), '/login');