VYPR
High severity7.5NVD Advisory· Published Nov 13, 2024· Updated Apr 15, 2026

CVE-2024-51996

CVE-2024-51996

Description

Symphony process is a module for the Symphony PHP framework which executes commands in sub-processes. When consuming a persisted remember-me cookie, Symfony does not check if the username persisted in the database matches the username attached with the cookie, leading to authentication bypass. This vulnerability is fixed in 5.4.47, 6.4.15, and 7.1.8.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
symfony/security-httpPackagist
>= 5.3.0, < 5.4.475.4.47
symfony/security-httpPackagist
>= 6.0.0-BETA1, < 6.4.156.4.15
symfony/security-httpPackagist
>= 7.0.0-BETA1, < 7.1.87.1.8

Patches

4
81354d392c5f

[security-http] Check owner of persisted remember-me cookie

https://github.com/symfony/symfonyJérémy DerusséNov 7, 2024via ghsa
2 files changed · +48 5
  • src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php+16 3 modified
    @@ -66,9 +66,16 @@ public function consumeRememberMeCookie(RememberMeDetails $rememberMeDetails): U
                 throw new AuthenticationException('The cookie is incorrectly formatted.');
             }
     
    -        [$series, $tokenValue] = explode(':', $rememberMeDetails->getValue());
    +        [$series, $tokenValue] = explode(':', $rememberMeDetails->getValue(), 2);
             $persistentToken = $this->tokenProvider->loadTokenBySeries($series);
     
    +        if ($persistentToken->getUserIdentifier() !== $rememberMeDetails->getUserIdentifier() || $persistentToken->getClass() !== $rememberMeDetails->getUserFqcn()) {
    +            throw new AuthenticationException('The cookie\'s hash is invalid.');
    +        }
    +
    +        // content of $rememberMeDetails is not trustable. this prevents use of this class
    +        unset($rememberMeDetails);
    +
             if ($this->tokenVerifier) {
                 $isTokenValid = $this->tokenVerifier->verifyToken($persistentToken, $tokenValue);
             } else {
    @@ -78,11 +85,17 @@ public function consumeRememberMeCookie(RememberMeDetails $rememberMeDetails): U
                 throw new CookieTheftException('This token was already used. The account is possibly compromised.');
             }
     
    -        if ($persistentToken->getLastUsed()->getTimestamp() + $this->options['lifetime'] < time()) {
    +        $expires = $persistentToken->getLastUsed()->getTimestamp() + $this->options['lifetime'];
    +        if ($expires < time()) {
                 throw new AuthenticationException('The cookie has expired.');
             }
     
    -        return parent::consumeRememberMeCookie($rememberMeDetails->withValue($persistentToken->getLastUsed()->getTimestamp().':'.$rememberMeDetails->getValue().':'.$persistentToken->getClass()));
    +        return parent::consumeRememberMeCookie(new RememberMeDetails(
    +            $persistentToken->getClass(),
    +            $persistentToken->getUserIdentifier(),
    +            $expires,
    +            $persistentToken->getLastUsed()->getTimestamp().':'.$series.':'.$tokenValue.':'.$persistentToken->getClass()
    +        ));
         }
     
         public function processRememberMe(RememberMeDetails $rememberMeDetails, UserInterface $user): void
    
  • src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php+32 2 modified
    @@ -80,7 +80,7 @@ public function testConsumeRememberMeCookieValid()
             $this->tokenProvider->expects($this->any())
                 ->method('loadTokenBySeries')
                 ->with('series1')
    -            ->willReturn(new PersistentToken(InMemoryUser::class, 'wouter', 'series1', 'tokenvalue', new \DateTime('-10 min')))
    +            ->willReturn(new PersistentToken(InMemoryUser::class, 'wouter', 'series1', 'tokenvalue', $lastUsed = new \DateTime('-10 min')))
             ;
     
             $this->tokenProvider->expects($this->once())->method('updateToken')->with('series1');
    @@ -98,11 +98,41 @@ public function testConsumeRememberMeCookieValid()
     
             $this->assertSame($rememberParts[0], $cookieParts[0]); // class
             $this->assertSame($rememberParts[1], $cookieParts[1]); // identifier
    -        $this->assertSame($rememberParts[2], $cookieParts[2]); // expire
    +        $this->assertEqualsWithDelta($lastUsed->getTimestamp() + 31536000, (int) $cookieParts[2], 2); // expire
             $this->assertNotSame($rememberParts[3], $cookieParts[3]); // value
             $this->assertSame(explode(':', $rememberParts[3])[0], explode(':', $cookieParts[3])[0]); // series
         }
     
    +    public function testConsumeRememberMeCookieInvalidOwner()
    +    {
    +        $this->tokenProvider->expects($this->any())
    +            ->method('loadTokenBySeries')
    +            ->with('series1')
    +            ->willReturn(new PersistentToken(InMemoryUser::class, 'wouter', 'series1', 'tokenvalue', new \DateTime('-10 min')))
    +        ;
    +
    +        $rememberMeDetails = new RememberMeDetails(InMemoryUser::class, 'jeremy', 360, 'series1:tokenvalue');
    +
    +        $this->expectException(AuthenticationException::class);
    +        $this->expectExceptionMessage('The cookie\'s hash is invalid.');
    +        $this->handler->consumeRememberMeCookie($rememberMeDetails);
    +    }
    +
    +    public function testConsumeRememberMeCookieInvalidValue()
    +    {
    +        $this->tokenProvider->expects($this->any())
    +            ->method('loadTokenBySeries')
    +            ->with('series1')
    +            ->willReturn(new PersistentToken(InMemoryUser::class, 'wouter', 'series1', 'tokenvalue', new \DateTime('-10 min')))
    +        ;
    +
    +        $rememberMeDetails = new RememberMeDetails(InMemoryUser::class, 'wouter', 360, 'series1:tokenvalue:somethingelse');
    +
    +        $this->expectException(AuthenticationException::class);
    +        $this->expectExceptionMessage('This token was already used. The account is possibly compromised.');
    +        $this->handler->consumeRememberMeCookie($rememberMeDetails);
    +    }
    +
         public function testConsumeRememberMeCookieValidByValidatorWithoutUpdate()
         {
             $verifier = $this->createMock(TokenVerifierInterface::class);
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.