Skip to content
/ core Public

Commit a659cc8

Browse files
committed
[SECURITY] Disallow changing system maintainer details
This change disallows changing any details of system maintainers in case the current user does not have system maintainer privileges as well. Resolves: #106129 Releases: main, 13.4, 12.4 Change-Id: I0a62809287bfddb582c2bf005c129bf07d16a63d Security-Bulletin: TYPO3-CORE-SA-2025-016 Security-References: CVE-2025-47940 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/89470 Tested-by: Oliver Hader <oliver.hader@typo3.org> Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
1 parent c265bee commit a659cc8

5 files changed

Lines changed: 64 additions & 31 deletions

File tree

Classes/DataHandling/DataHandler.php

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,33 +1274,6 @@ public function checkValue($table, $field, $value, $id, $status, $realPid, $tscP
12741274
}
12751275
}
12761276

1277-
if ($table === 'be_users'
1278-
&& ($field === 'admin' || $field === 'password')
1279-
&& $status === 'update'
1280-
) {
1281-
// Do not allow a non system maintainer admin to change admin flag and password of system maintainers
1282-
$systemMaintainers = array_map(intval(...), $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] ?? []);
1283-
// False if current user is not in system maintainer list or if switch to user mode is active
1284-
$isCurrentUserSystemMaintainer = $this->BE_USER->isSystemMaintainer();
1285-
$isTargetUserInSystemMaintainerList = in_array((int)$id, $systemMaintainers, true);
1286-
if ($field === 'admin') {
1287-
$isFieldChanged = (int)$currentRecord[$field] !== (int)$value;
1288-
} else {
1289-
$isFieldChanged = $currentRecord[$field] !== $value;
1290-
}
1291-
if (!$isCurrentUserSystemMaintainer && $isTargetUserInSystemMaintainerList && $isFieldChanged) {
1292-
$value = $currentRecord[$field];
1293-
$this->log(
1294-
$table,
1295-
(int)$id,
1296-
SystemLogDatabaseAction::UPDATE,
1297-
null,
1298-
SystemLogErrorClassification::SECURITY_NOTICE,
1299-
'Only system maintainers can change the admin flag and password of other system maintainers. The value has not been updated'
1300-
);
1301-
}
1302-
}
1303-
13041277
// Getting config for the field
13051278
$tcaFieldConf = $this->resolveFieldConfigurationAndRespectColumnsOverrides($table, $field);
13061279

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the TYPO3 CMS project.
7+
*
8+
* It is free software; you can redistribute it and/or modify it under
9+
* the terms of the GNU General Public License, either version 2
10+
* of the License, or any later version.
11+
*
12+
* For the full copyright and license information, please read the
13+
* LICENSE.txt file that was distributed with this source code.
14+
*
15+
* The TYPO3 project - inspiring people to share!
16+
*/
17+
18+
namespace TYPO3\CMS\Core\Hooks;
19+
20+
use TYPO3\CMS\Core\DataHandling\DataHandler;
21+
use TYPO3\CMS\Core\SysLog\Action\Database as SystemLogDatabaseAction;
22+
use TYPO3\CMS\Core\SysLog\Error as SystemLogErrorClassification;
23+
24+
/**
25+
* DataHandler hook to ensure that only system maintainers can change details of system maintainers.
26+
*
27+
* @internal This class is a hook implementation and is not part of the TYPO3 Core API.
28+
*/
29+
final class SystemMaintainerAllowanceCheck
30+
{
31+
public function processDatamap_postProcessFieldArray(string $status, string $table, int|string $id, array &$fieldArray, DataHandler $dataHandler): void
32+
{
33+
if ($table !== 'be_users' || $status !== 'update' || empty($fieldArray)) {
34+
return;
35+
}
36+
// Do not allow a non system maintainer admin to change details of system maintainers.
37+
$systemMaintainers = array_map(intval(...), $GLOBALS['TYPO3_CONF_VARS']['SYS']['systemMaintainers'] ?? []);
38+
// False if current user is not in system maintainer list or if switch to user mode is active
39+
$isCurrentUserSystemMaintainer = $dataHandler->BE_USER->isSystemMaintainer();
40+
$isTargetUserInSystemMaintainerList = in_array((int)$id, $systemMaintainers, true);
41+
if (!$isCurrentUserSystemMaintainer && $isTargetUserInSystemMaintainerList) {
42+
$fieldArray = [];
43+
$dataHandler->log(
44+
$table,
45+
(int)$id,
46+
SystemLogDatabaseAction::UPDATE,
47+
null,
48+
SystemLogErrorClassification::SECURITY_NOTICE,
49+
'Only system maintainers can change details of other system maintainers. The values have not been updated.'
50+
);
51+
}
52+
}
53+
}

Configuration/DefaultConfiguration.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,11 @@
726726
\TYPO3\CMS\Backend\Form\FormDataProvider\TcaRecordTitle::class,
727727
],
728728
],
729+
\TYPO3\CMS\Backend\Form\FormDataProvider\SystemMaintainerAsReadonly::class => [
730+
'depends' => [
731+
\TYPO3\CMS\Backend\Form\FormDataProvider\EvaluateDisplayConditions::class,
732+
],
733+
],
729734
],
730735
'tcaSelectTreeAjaxFieldData' => [
731736
\TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseEditRow::class => [],

Resources/Private/Language/locallang_core.xlf

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,17 +1366,17 @@ Do you want to refresh it now?</source>
13661366
<source>"%s" is not a valid e-mail address.</source>
13671367
</trans-unit>
13681368
<trans-unit id="error.adminCanNotChangeSystemMaintainer">
1369-
<source>Only system maintainers can change the admin flag and password of other system maintainers. The value has not been updated.</source>
1369+
<source>Non system maintainers cannot change details of system maintainers. The values have not been updated.</source>
1370+
</trans-unit>
1371+
<trans-unit id="formEngine.beUser.information.adminCanNotChangeSystemMaintainer">
1372+
<source>This user is a system maintainer. Changing details of system maintainers is not allowed.</source>
13701373
</trans-unit>
13711374
<trans-unit id="formEngine.beUser.admin.information.userIsSystemMaintainer">
13721375
<source>This user is a system maintainer</source>
13731376
</trans-unit>
13741377
<trans-unit id="formEngine.beUser.admin.information.userWillBecomeSystemMaintainer">
13751378
<source>This user is in the list of allowed system maintainers and will gain system level access if enabling admin access.</source>
13761379
</trans-unit>
1377-
<trans-unit id="formEngine.beUser.admin.information.userAdminAndPasswordChangeNotAllowed">
1378-
<source>This user is a system maintainer. Changing the admin flag and changing password is denied.</source>
1379-
</trans-unit>
13801380
<trans-unit id="formEngine.pages.backendLayout.information.inheritFromParentPage">
13811381
<source>This page will most likely use backend layout "%s", inherited from a parent page.</source>
13821382
</trans-unit>

ext_localconf.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use TYPO3\CMS\Core\Hooks\CreateSiteConfiguration;
99
use TYPO3\CMS\Core\Hooks\DestroySessionHook;
1010
use TYPO3\CMS\Core\Hooks\PagesTsConfigGuard;
11+
use TYPO3\CMS\Core\Hooks\SystemMaintainerAllowanceCheck;
1112
use TYPO3\CMS\Core\Hooks\UpdateFileIndexEntry;
1213
use TYPO3\CMS\Core\MetaTag\EdgeMetaTagManager;
1314
use TYPO3\CMS\Core\MetaTag\Html5MetaTagManager;
@@ -32,6 +33,7 @@
3233
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS'][GeneralUtility::class]['moveUploadedFile'][] = SvgHookHandler::class . '->processMoveUploadedFile';
3334
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = FileMetadataPermissionsAspect::class;
3435
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = BackendUserPasswordCheck::class;
36+
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = SystemMaintainerAllowanceCheck::class;
3537
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['checkModifyAccessList'][] = FileMetadataPermissionsAspect::class;
3638
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['checkModifyAccessList'][] = FilePermissionAspect::class;
3739
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass'][] = FilePermissionAspect::class;

0 commit comments

Comments
 (0)