CVE-2023-45659: Insufficient Session Expiration (CWE-613)
value: Engelsystem is a shift planning system for chaos events.  If a users' password is compromised and an attacker gained access to a users' account, i.e., logged in and obtained a session, an attackers' session is not terminated if the users' account password is reset. This vulnerability has been fixed in the commit `dbb089315ff3d`. Users are advised to update their installations. There are no known workarounds for this vulnerability.
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: 2.8
Published: 2023-10-17T00:15Z
Repository: https://github.com/engelsystem/engelsystem
Language: PHP
Files changed: src/Controllers/PasswordResetController.php, tests/Unit/Controllers/PasswordResetControllerTest.php
Commit date: 2023-09-18 18:10:40 +0200
Commit message: Delete all sessions on password reset

Diff: diff --git a/src/Controllers/PasswordResetController.php b/src/Controllers/PasswordResetController.php
index 694d4e0b..70a53d00 100644
--- a/src/Controllers/PasswordResetController.php
+++ b/src/Controllers/PasswordResetController.php
@@ -94,10 +94,12 @@ class PasswordResetController extends BaseController
         }
 
         auth()->setPassword($reset->user, $data['password']);
         $reset->delete();
 
+        $reset->user->sessions()->getQuery()->delete();
+
         return $this->showView('pages/password/reset-success', ['type' => 'reset']);
     }
 
     protected function showView(string $view = 'pages/password/reset', array $data = []): Response
     {
diff --git a/tests/Unit/Controllers/PasswordResetControllerTest.php b/tests/Unit/Controllers/PasswordResetControllerTest.php
index c653f3c0..d714177c 100644
--- a/tests/Unit/Controllers/PasswordResetControllerTest.php
+++ b/tests/Unit/Controllers/PasswordResetControllerTest.php
@@ -13,10 +13,11 @@ use Engelsystem\Http\Exceptions\HttpNotFound;
 use Engelsystem\Http\Exceptions\ValidationException;
 use Engelsystem\Http\Request;
 use Engelsystem\Http\Response;
 use Engelsystem\Http\Validation\Validator;
 use Engelsystem\Mail\EngelsystemMailer;
+use Engelsystem\Models\Session as SessionModel;
 use Engelsystem\Models\User\PasswordReset;
 use Engelsystem\Models\User\User;
 use Engelsystem\Renderer\Renderer;
 use Engelsystem\Test\Unit\HasDatabase;
 use PHPUnit\Framework\MockObject\MockObject;
@@ -145,10 +146,12 @@ class PasswordResetControllerTest extends ControllerTest
         $request = new Request(
             [],
             ['password' => $password, 'password_confirmation' => $password],
             ['token' => $token->token]
         );
+        SessionModel::factory()->create(); // Some other session
+        SessionModel::factory(3)->create(['user_id' => $user->id]);
 
         $controller = $this->getController(
             'pages/password/reset-success',
             ['type' => 'reset']
         );
@@ -160,10 +163,16 @@ class PasswordResetControllerTest extends ControllerTest
         $this->assertEquals(200, $response->getStatusCode());
 
         $this->assertEmpty((new PasswordReset())->find($user->id));
         $this->assertNotNull(auth()->authenticate($user->name, $password));
         $this->assertHasNoNotifications();
+
+        $this->assertEmpty(
+            SessionModel::whereUserId($user->id)->get(),
+            'All user sessions should be deleted after successful password reset'
+        );
+        $this->assertCount(1, SessionModel::all()); // Another session should be still there
     }
 
     /**
      * @covers \Engelsystem\Controllers\PasswordResetController::postResetPassword
      * @covers \Engelsystem\Controllers\PasswordResetController::showView

Fixed code:         $reset->user->sessions()->getQuery()->delete();

use Engelsystem\Models\Session as SessionModel;
        SessionModel::factory()->create(); // Some other session
        SessionModel::factory(3)->create(['user_id' => $user->id]);

        $this->assertEmpty(
            SessionModel::whereUserId($user->id)->get(),
            'All user sessions should be deleted after successful password reset'
        );
        $this->assertCount(1, SessionModel::all()); // Another session should be still there