CVE-2023-5865: Insufficient Session Expiration (CWE-613)
value: Insufficient Session Expiration in GitHub repository thorsten/phpmyfaq prior to 3.2.2.
CWE description: According to WASC, "Insufficient Session Expiration is when a web site permits an attacker to reuse old session credentials or session IDs for authorization."
CVSS v3 base score: 9.8
Published: 2023-10-31T01:15Z
Repository: https://github.com/thorsten/phpmyfaq
Language: PHP
Files changed: phpmyfaq/admin/api/user.php, phpmyfaq/admin/assets/src/user/user-list.js, phpmyfaq/admin/user.php, phpmyfaq/src/phpMyFAQ/User.php
Commit date: 2023-09-22 21:55:18 +0200
Commit message: fix: terminate user sessions for user with changed permissions

Diff: diff --git a/phpmyfaq/admin/api/user.php b/phpmyfaq/admin/api/user.php
index 5841e7821c2..786f00b9e16 100644
--- a/phpmyfaq/admin/api/user.php
+++ b/phpmyfaq/admin/api/user.php
@@ -113,12 +113,11 @@ if (
             $response->send();
             break;
 
         case 'activate_user':
             $postData = json_decode(file_get_contents('php://input', true));
-
-            if (!Token::getInstance()->verifyToken('user', $postData->csrfToken)) {
+            if (!Token::getInstance()->verifyToken('activate-user', $postData->csrfToken)) {
                 $response->setStatusCode(Response::HTTP_UNAUTHORIZED);
                 $response->setData(['error' => Translation::get('err_NotAuth')]);
                 $response->send();
                 exit(1);
             }
diff --git a/phpmyfaq/admin/assets/src/user/user-list.js b/phpmyfaq/admin/assets/src/user/user-list.js
index b551bd7562e..d72c0a4f0e5 100644
--- a/phpmyfaq/admin/assets/src/user/user-list.js
+++ b/phpmyfaq/admin/assets/src/user/user-list.js
@@ -16,11 +16,11 @@
  */
 
 import { addElement } from '../../../../assets/src/utils';
 
 const activateUser = (userId, csrfToken) => {
-  fetch('index.php?action=ajax&ajax=user&ajaxaction=delete_user', {
+  fetch('index.php?action=ajax&ajax=user&ajaxaction=activate_user', {
     method: 'POST',
     headers: {
       Accept: 'application/json, text/plain, */*',
       'Content-Type': 'application/json',
     },
diff --git a/phpmyfaq/admin/user.php b/phpmyfaq/admin/user.php
index 468688fb450..95de52b9500 100755
--- a/phpmyfaq/admin/user.php
+++ b/phpmyfaq/admin/user.php
@@ -92,11 +92,14 @@ if (
                 $message .= Alert::danger('ad_msg_mysqlerr');
             }
             foreach ($userRights as $rightId) {
                 $perm->grantUserRight($userId, $rightId);
             }
+
             $idUser = $user->getUserById($userId, true);
+            // Terminate session in case of different permissions after the update
+            $user->terminateSessionId();
             $message .= sprintf(
                 '<p class="alert alert-success">%s <strong>%s</strong> %s</p>',
                 Translation::get('ad_msg_savedsuc_1'),
                 Strings::htmlentities($user->getLogin(), ENT_QUOTES),
                 Translation::get('ad_msg_savedsuc_2')
diff --git a/phpmyfaq/src/phpMyFAQ/User.php b/phpmyfaq/src/phpMyFAQ/User.php
index 4294fd9445d..35ae4ec1711 100644
--- a/phpmyfaq/src/phpMyFAQ/User.php
+++ b/phpmyfaq/src/phpMyFAQ/User.php
@@ -1035,6 +1035,21 @@ class User
             return true;
         }
 
         return false;
     }
+
+    /**
+     * Terminates the session ID of user
+     * @return bool
+     */
+    public function terminateSessionId(): bool
+    {
+        $update = sprintf(
+            "UPDATE %sfaquser SET session_id = '' WHERE user_id = %d",
+            Database::getTablePrefix(),
+            $this->userId
+        );
+
+        return (bool) $this->config->getDb()->query($update);
+    }
 }

Vulnerable code: 
            if (!Token::getInstance()->verifyToken('user', $postData->csrfToken)) {
  fetch('index.php?action=ajax&ajax=user&ajaxaction=delete_user', {
Fixed code:             if (!Token::getInstance()->verifyToken('activate-user', $postData->csrfToken)) {
  fetch('index.php?action=ajax&ajax=user&ajaxaction=activate_user', {

            // Terminate session in case of different permissions after the update
            $user->terminateSessionId();

    /**
     * Terminates the session ID of user
     * @return bool
     */
    public function terminateSessionId(): bool
    {
        $update = sprintf(
            "UPDATE %sfaquser SET session_id = '' WHERE user_id = %d",
            Database::getTablePrefix(),
            $this->userId
        );

        return (bool) $this->config->getDb()->query($update);
    }