CVE-2024-30262: Insufficient Information (NVD-CWE-noinfo)
value: Contao is an open source content management system. Prior to version 4.13.40, when a frontend member changes their password in the personal data or the password lost module, the corresponding remember-me tokens are not removed. If someone compromises an account and is able to get a remember-me token, changing the password would not be enough to reclaim control over the account. Version 4.13.40 contains a fix for the issue. As a workaround, disable "Allow auto login" in the login module.

CWE description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
Published: 2024-04-09T17:16Z
Repository: https://github.com/contao/contao
Language: PHP
Files changed: core-bundle/src/Repository/RememberMeRepository.php, core-bundle/src/Resources/config/services.yml, core-bundle/src/Resources/contao/modules/ModuleChangePassword.php, core-bundle/src/Resources/contao/modules/ModulePassword.php, core-bundle/src/Resources/contao/modules/ModulePersonalData.php
Commit date: 2024-04-09 07:18:49 +0200
Commit message: Merge pull request from GHSA-r4r6-j2j3-7pp5

Co-authored-by: Leo Feyer <1192057+leofeyer@users.noreply.github.com>
Diff: diff --git a/core-bundle/src/Repository/RememberMeRepository.php b/core-bundle/src/Repository/RememberMeRepository.php
index 58b28badda7..15c81efd5ad 100644
--- a/core-bundle/src/Repository/RememberMeRepository.php
+++ b/core-bundle/src/Repository/RememberMeRepository.php
@@ -117,6 +117,18 @@ class RememberMeRepository extends ServiceEntityRepository
             $this->_em->persist($entity);
         }
 
         $this->_em->flush();
     }
+
+    public function deleteByUsername(string $username): void
+    {
+        $qb = $this->_em->createQueryBuilder();
+        $qb
+            ->delete($this->_entityName, 'rm')
+            ->where('rm.username = :username')
+            ->setParameter('username', $username)
+        ;
+
+        $qb->getQuery()->execute();
+    }
 }
diff --git a/core-bundle/src/Resources/config/services.yml b/core-bundle/src/Resources/config/services.yml
index ef19469d1bf..2ff64a78e29 100644
--- a/core-bundle/src/Resources/config/services.yml
+++ b/core-bundle/src/Resources/config/services.yml
@@ -525,10 +525,11 @@ services:
         arguments:
             - '@doctrine'
 
     contao.repository.remember_me:
         class: Contao\CoreBundle\Repository\RememberMeRepository
+        public: true
         arguments:
             - '@doctrine'
 
     contao.resource_finder:
         class: Contao\CoreBundle\Config\ResourceFinder
diff --git a/core-bundle/src/Resources/contao/modules/ModuleChangePassword.php b/core-bundle/src/Resources/contao/modules/ModuleChangePassword.php
index 613a10f053c..b408ac3a4e9 100644
--- a/core-bundle/src/Resources/contao/modules/ModuleChangePassword.php
+++ b/core-bundle/src/Resources/contao/modules/ModuleChangePassword.php
@@ -176,10 +176,12 @@ class ModuleChangePassword extends Module
 		{
 			$objMember->tstamp = time();
 			$objMember->password = $objNewPassword->value;
 			$objMember->save();
 
+			System::getContainer()->get('contao.repository.remember_me')->deleteByUsername($objMember->username);
+
 			// Create a new version
 			if ($GLOBALS['TL_DCA'][$strTable]['config']['enableVersioning'] ?? null)
 			{
 				$objVersions->create();
 			}
diff --git a/core-bundle/src/Resources/contao/modules/ModulePassword.php b/core-bundle/src/Resources/contao/modules/ModulePassword.php
index ea7140aeddb..53895306a34 100644
--- a/core-bundle/src/Resources/contao/modules/ModulePassword.php
+++ b/core-bundle/src/Resources/contao/modules/ModulePassword.php
@@ -257,10 +257,12 @@ class ModulePassword extends Module
 				$objMember->tstamp = time();
 				$objMember->locked = 0; // see #8545
 				$objMember->password = $objWidget->value;
 				$objMember->save();
 
+				System::getContainer()->get('contao.repository.remember_me')->deleteByUsername($objMember->username);
+
 				$optInToken->confirm();
 
 				// Create a new version
 				if ($GLOBALS['TL_DCA']['tl_member']['config']['enableVersioning'] ?? null)
 				{
diff --git a/core-bundle/src/Resources/contao/modules/ModulePersonalData.php b/core-bundle/src/Resources/contao/modules/ModulePersonalData.php
index 0b234fb4567..55ecefdc6f9 100644
--- a/core-bundle/src/Resources/contao/modules/ModulePersonalData.php
+++ b/core-bundle/src/Resources/contao/modules/ModulePersonalData.php
@@ -301,10 +301,15 @@ class ModulePersonalData extends Module
 						$this->User->$field = $varValue;
 
 						// Set the new field in the member model
 						$blnModified = true;
 						$objMember->$field = $varValue;
+
+						if ($objWidget instanceof FormPassword)
+						{
+							System::getContainer()->get('contao.repository.remember_me')->deleteByUsername($objMember->username);
+						}
 					}
 				}
 			}
 
 			if ($objWidget instanceof UploadableWidgetInterface)

Fixed code: 
    public function deleteByUsername(string $username): void
    {
        $qb = $this->_em->createQueryBuilder();
        $qb
            ->delete($this->_entityName, 'rm')
            ->where('rm.username = :username')
            ->setParameter('username', $username)
        ;

        $qb->getQuery()->execute();
    }
        public: true
			System::getContainer()->get('contao.repository.remember_me')->deleteByUsername($objMember->username);

				System::getContainer()->get('contao.repository.remember_me')->deleteByUsername($objMember->username);


						if ($objWidget instanceof FormPassword)
						{
							System::getContainer()->get('contao.repository.remember_me')->deleteByUsername($objMember->username);
						}