diff --git a/typo3/sysext/install/Classes/Controller/BackendModuleController.php b/typo3/sysext/install/Classes/Controller/BackendModuleController.php
index 4d76a340c87ce507c4cde66818bdcf36f7da1e70..4476817d10ca174d878a3b999018463925413739 100644
--- a/typo3/sysext/install/Classes/Controller/BackendModuleController.php
+++ b/typo3/sysext/install/Classes/Controller/BackendModuleController.php
@@ -204,7 +204,7 @@ class BackendModuleController
      */
     protected function setAuthorizedAndRedirect(string $controller): ResponseInterface
     {
-        $this->getSessionService()->setAuthorizedBackendSession();
+        $this->getSessionService()->setAuthorizedBackendSession($this->getBackendUser());
         $redirectLocation = 'install.php?install[controller]=' . $controller . '&install[context]=backend';
         return new RedirectResponse($redirectLocation, 303);
     }
diff --git a/typo3/sysext/install/Classes/Middleware/Maintenance.php b/typo3/sysext/install/Classes/Middleware/Maintenance.php
index 335543a515980adcf3b87b84e3a14d35bec7a4bb..32ab1714b4519c08639058ea9bc49c388f6dbc30 100644
--- a/typo3/sysext/install/Classes/Middleware/Maintenance.php
+++ b/typo3/sysext/install/Classes/Middleware/Maintenance.php
@@ -145,6 +145,21 @@ class Maintenance implements MiddlewareInterface
 
         // session related actions
         $session = new SessionService();
+
+        // the backend user has an active session but the admin / maintainer
+        // rights have been revoked or the user was disabled or deleted in the meantime
+        if ($session->isAuthorizedBackendUserSession() && !$session->hasActiveBackendUserRoleAndSession()) {
+            // log out the user and destroy the session
+            $session->resetSession();
+            $session->destroySession();
+            $formProtection = FormProtectionFactory::get(
+                InstallToolFormProtection::class
+            );
+            $formProtection->clean();
+
+            return new HtmlResponse('', 403);
+        }
+
         if ($actionName === 'preAccessCheck') {
             $response = new JsonResponse([
                 'installToolLocked' => !$this->checkEnableInstallToolFile(),
diff --git a/typo3/sysext/install/Classes/Service/SessionService.php b/typo3/sysext/install/Classes/Service/SessionService.php
index 2ec76f019021da009e795e7323e67214a6f3d88b..a85342c0209928a251178a718ae7314820e59b47 100644
--- a/typo3/sysext/install/Classes/Service/SessionService.php
+++ b/typo3/sysext/install/Classes/Service/SessionService.php
@@ -15,11 +15,19 @@
 
 namespace TYPO3\CMS\Install\Service;
 
+use Doctrine\DBAL\FetchMode;
 use Symfony\Component\HttpFoundation\Cookie;
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Core\Environment;
+use TYPO3\CMS\Core\Database\ConnectionPool;
+use TYPO3\CMS\Core\Database\Query\Restriction\DefaultRestrictionContainer;
+use TYPO3\CMS\Core\Database\Query\Restriction\RootLevelRestriction;
 use TYPO3\CMS\Core\Http\CookieHeaderTrait;
 use TYPO3\CMS\Core\Messaging\FlashMessage;
 use TYPO3\CMS\Core\Security\BlockSerializationTrait;
+use TYPO3\CMS\Core\Session\Backend\HashableSessionBackendInterface;
+use TYPO3\CMS\Core\Session\Backend\SessionBackendInterface;
+use TYPO3\CMS\Core\Session\SessionManager;
 use TYPO3\CMS\Core\SingletonInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
 use TYPO3\CMS\Install\Exception;
@@ -202,14 +210,28 @@ class SessionService implements SingletonInterface
     /**
      * Marks this session as an "authorized by backend user" one.
      * This is called by BackendModuleController from backend context.
+     *
+     * @param BackendUserAuthentication $backendUser current backend user
      */
-    public function setAuthorizedBackendSession()
+    public function setAuthorizedBackendSession(BackendUserAuthentication $backendUser)
     {
+        $nonce = bin2hex(random_bytes(20));
+        $sessionBackend = $this->getBackendUserSessionBackend();
+        // use hash mechanism of session backend, or pass plain value through generic hmac
+        $sessionHmac = $sessionBackend instanceof HashableSessionBackendInterface
+            ? $sessionBackend->hash($backendUser->id)
+            : hash_hmac('sha256', $backendUser->id, $nonce);
+
         $_SESSION['authorized'] = true;
         $_SESSION['lastSessionId'] = time();
         $_SESSION['tstamp'] = time();
         $_SESSION['expires'] = time() + $this->expireTimeInMinutes * 60;
         $_SESSION['isBackendSession'] = true;
+        $_SESSION['backendUserSession'] = [
+            'nonce' => $nonce,
+            'userId' => (int)$backendUser->user['uid'],
+            'hmac' => $sessionHmac,
+        ];
         // Renew the session id to avoid session fixation
         $this->renewSession();
     }
@@ -236,7 +258,7 @@ class SessionService implements SingletonInterface
      *
      * @return bool TRUE if this session has been authorized before and initialized by a backend system maintainer
      */
-    public function isAuthorizedBackendUserSession()
+    public function isAuthorizedBackendUserSession(): bool
     {
         if (!$this->hasSessionCookie()) {
             return false;
@@ -248,6 +270,49 @@ class SessionService implements SingletonInterface
         return !$this->isExpired();
     }
 
+    /**
+     * Evaluates whether the backend user that initiated this admin tool session,
+     * has an active role (is still admin & system maintainer) and has an active backend user interface session.
+     *
+     * @return bool whether the backend user has an active role and backend user interface session
+     */
+    public function hasActiveBackendUserRoleAndSession(): bool
+    {
+        // @see \TYPO3\CMS\Install\Controller\BackendModuleController::setAuthorizedAndRedirect()
+        $backendUserSession = $this->getBackendUserSession();
+        $backendUserRecord = $this->getBackendUserRecord($backendUserSession['userId']);
+        if ($backendUserRecord === null || empty($backendUserRecord['uid'])) {
+            return false;
+        }
+        $isAdmin = (($backendUserRecord['admin'] ?? 0) & 1) === 1;
+        $systemMaintainers = array_map('intval', $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] ?? []);
+        // stop here, in case the current admin tool session does not belong to a backend user having admin & maintainer privileges
+        if (!$isAdmin || !in_array((int)$backendUserRecord['uid'], $systemMaintainers, true)) {
+            return false;
+        }
+
+        $sessionBackend = $this->getBackendUserSessionBackend();
+        foreach ($sessionBackend->getAll() as $sessionRecord) {
+            $sessionUserId = (int)($sessionRecord['ses_userid'] ?? 0);
+            // skip, in case backend user id does not match
+            if ($backendUserSession['userId'] !== $sessionUserId) {
+                continue;
+            }
+            $sessionId = (string)($sessionRecord['ses_id'] ?? '');
+            // use persisted hashed `ses_id` directly, or pass through hmac for plain values
+            $sessionHmac = $sessionBackend instanceof HashableSessionBackendInterface
+                ? $sessionId
+                : hash_hmac('sha256', $sessionId, $backendUserSession['nonce']);
+            // skip, in case backend user session id does not match
+            if ($backendUserSession['hmac'] !== $sessionHmac) {
+                continue;
+            }
+            // backend user id and session id matched correctly
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Check if our session is expired.
      * Useful only right after a FALSE "isAuthorized" to see if this is the
@@ -313,6 +378,20 @@ class SessionService implements SingletonInterface
         return $messages;
     }
 
+    /**
+     * @return array{userId: int, nonce: string, hmac: string} backend user session references
+     */
+    public function getBackendUserSession(): array
+    {
+        if (empty($_SESSION['backendUserSession'])) {
+            throw new Exception(
+                'The backend user session is only available if invoked via the backend user interface.',
+                1624879295
+            );
+        }
+        return $_SESSION['backendUserSession'];
+    }
+
     /**
      * Check if php session.auto_start is enabled
      *
@@ -337,4 +416,52 @@ class SessionService implements SingletonInterface
             [FILTER_REQUIRE_SCALAR, FILTER_NULL_ON_FAILURE]
         );
     }
+
+    /**
+     * Fetching a user record with uid=$uid.
+     * Functionally similar to TYPO3\CMS\Core\Authentication\BackendUserAuthentication::setBeUserByUid().
+     *
+     * @param int $uid The UID of the backend user
+     * @return array<string, int>|null The backend user record or NULL
+     */
+    protected function getBackendUserRecord(int $uid): ?array
+    {
+        $restrictionContainer = GeneralUtility::makeInstance(DefaultRestrictionContainer::class);
+        $restrictionContainer->add(GeneralUtility::makeInstance(RootLevelRestriction::class, ['be_users']));
+
+        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('be_users');
+        $queryBuilder->setRestrictions($restrictionContainer);
+        $queryBuilder->select('uid', 'admin')
+            ->from('be_users')
+            ->where($queryBuilder->expr()->eq('uid', $queryBuilder->createNamedParameter($uid, \PDO::PARAM_INT)));
+
+        $resetBeUsersTca = false;
+        if (!isset($GLOBALS['TCA']['be_users'])) {
+            // The admin tool intentionally does not load any TCA information at this time.
+            // The database restictions, needs the enablecolumns TCA information
+            // for 'be_users' to load the user correctly.
+            // That is why this part of the TCA ($GLOBALS['TCA']['be_users']['ctrl']['enablecolumns'])
+            // is simulated.
+            // The simulation state will be removed later to avoid unexpected side effects.
+            $GLOBALS['TCA']['be_users']['ctrl']['enablecolumns'] = [
+                'rootLevel' => 1,
+                'deleted' => 'deleted',
+                'disabled' => 'disable',
+                'starttime' => 'starttime',
+                'endtime' => 'endtime',
+            ];
+            $resetBeUsersTca = true;
+        }
+        $result = $queryBuilder->execute()->fetch(FetchMode::ASSOCIATIVE);
+        if ($resetBeUsersTca) {
+            unset($GLOBALS['TCA']['be_users']);
+        }
+
+        return is_array($result) ? $result : null;
+    }
+
+    protected function getBackendUserSessionBackend(): SessionBackendInterface
+    {
+        return GeneralUtility::makeInstance(SessionManager::class)->getSessionBackend('BE');
+    }
 }
diff --git a/typo3/sysext/install/Tests/Functional/Controller/BackendModuleControllerTest.php b/typo3/sysext/install/Tests/Functional/Controller/BackendModuleControllerTest.php
index c2cbe2a667d31e93ee49b85176845647fe4ffcba..fbe9fd063b5057a0585749a646d3e4bbfb83f411 100644
--- a/typo3/sysext/install/Tests/Functional/Controller/BackendModuleControllerTest.php
+++ b/typo3/sysext/install/Tests/Functional/Controller/BackendModuleControllerTest.php
@@ -17,6 +17,7 @@ declare(strict_types=1);
 
 namespace TYPO3\CMS\Install\Tests\Functional\Controller;
 
+use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
 use TYPO3\CMS\Core\Core\ApplicationContext;
 use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Install\Controller\BackendModuleController;
@@ -56,7 +57,13 @@ class BackendModuleControllerTest extends FunctionalTestCase
             Environment::isWindows() ? 'WINDOWS' : 'UNIX'
         );
 
-        // Authorized redirect to the install tool is performed, sudo mode is not required
+        // Authorized redirect to the admin tool is performed
+        // sudo mode is not required (due to development context)
+        $GLOBALS['BE_USER'] = new BackendUserAuthentication();
+        // using anonymous user session, which is fine for this test case
+        $GLOBALS['BE_USER']->id = $GLOBALS['BE_USER']->createSessionId();
+        $GLOBALS['BE_USER']->user = ['uid' => 1];
+
         $response = $subject->{$action}();
         self::assertEquals(303, $response->getStatusCode());
         self::assertNotEmpty($response->getHeader('location'));