Skip to content

Commit c9898d2

Browse files
derhansenohader
authored andcommitted
[SECURITY] Prevent unauthorized record move via DataHandler
With #106220, the DataHandler `moveRecord()` function has been refactored and access checks have been simplified. One access check has however been forgotten during the process leading to unauthorized movement of records. With this change, the missing check in DataHandler `moveRecord()` function has been re-added, so it is now checked again, if a user has edit permissions on the source page when moving a record to another page. Resolves: #108758 Related: #106220 Releases: main, 14.3, 13.4 Change-Id: I95a061ab68111b879c34d51bfbe76cfdf5a64be7 Security-Bulletin: TYPO3-CORE-SA-2026-012 Security-References: CVE-2026-47350 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/94413 Tested-by: Oliver Hader <oliver.hader@typo3.org> Reviewed-by: Oliver Hader <oliver.hader@typo3.org>
1 parent 9f17a30 commit c9898d2

3 files changed

Lines changed: 91 additions & 0 deletions

File tree

typo3/sysext/core/Classes/DataHandling/DataHandler.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4489,6 +4489,11 @@ public function moveRecord(string $table, int $uid, int $destination): void
44894489
}
44904490
} else {
44914491
if ($isMovingToDifferentPid) {
4492+
if (!$this->hasPermissionToUpdate($table, $sourcePageRecord)) {
4493+
// When record is moved to different target, update permissions on source page are needed
4494+
$this->log($table, $sourceUid, SystemLogDatabaseAction::MOVE, null, SystemLogErrorClassification::USER_ERROR, 'Attempt to move record {table}:{uid} to pid "{targetPid}" without having permissions to update the source page (uid={sourcePid})', null, ['table' => $table, 'uid' => $sourceUid, 'targetPid' => $updateFields['pid'], 'sourcePid' => $sourcePid], $sourcePid);
4495+
return;
4496+
}
44924497
if (!$this->hasPermissionToInsert($table, $updateFields['pid'], $targetPageRecord)) {
44934498
// When record is moved to different page, insert permissions on target are needed
44944499
$this->log($table, $sourceUid, SystemLogDatabaseAction::MOVE, null, SystemLogErrorClassification::USER_ERROR, 'Attempt to move record {table}:{uid} to pid "{targetPid}" without having permissions to insert', null, ['table' => $table, 'uid' => $sourceUid, 'targetPid' => $updateFields['pid']], $updateFields['pid']);
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
"pages"
2+
,"uid","pid","sorting","title","deleted","perms_everybody"
3+
,1,0,128,"Root 1",0,31
4+
,2,1,128,"Page 1",0,31
5+
,3,1,128,"Page 2",0,31
6+
,4,0,128,"Root 2",0,31
7+
,5,4,128,"Page 1",0,31
8+
tt_content,,,,,,,,
9+
,uid,pid,header,sys_language_uid,l18n_parent,assets,CType
10+
,1,2,"A Header on page uid 2",0,0,0,"header"
11+
,2,5,"A Header on page uid 4",0,0,0,"header"
12+
be_groups,,,,,,,,,
13+
,uid,pid,title,deleted,db_mountpoints,tables_select,tables_modify,non_exclude_fields,explicit_allowdeny
14+
,9,0,"editors",0,1,"pages,tt_content","pages,tt_content","pages:title,tt_content:header,tt_content:CType","tt_content:CType:header"
15+
"be_users",,,,,,,
16+
,"uid","pid","username","usergroup","deleted","admin","options"
17+
,9,0,"editor",9,0,0,3
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
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\Tests\Functional\DataHandling\DataHandler;
19+
20+
use PHPUnit\Framework\Attributes\Test;
21+
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
22+
use TYPO3\CMS\Core\DataHandling\DataHandler;
23+
use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
24+
25+
final class MoveActionTest extends FunctionalTestCase
26+
{
27+
private BackendUserAuthentication $backendUser;
28+
private DataHandler $subject;
29+
30+
protected function setUp(): void
31+
{
32+
parent::setUp();
33+
34+
$this->importCSVDataSet(__DIR__ . '/DataSet/MoveRecord.csv');
35+
36+
$this->backendUser = $this->setUpBackendUser(9);
37+
$this->backendUser->setWebmounts([1]);
38+
39+
$this->subject = $this->get(DataHandler::class);
40+
$this->subject->start([], []);
41+
}
42+
43+
#[Test]
44+
public function moveRecordOfAccessibleRecordIsPermitted(): void
45+
{
46+
$recordUid = 1;
47+
$targetPid = 3;
48+
$this->subject->moveRecord('tt_content', $recordUid, $targetPid);
49+
self::assertEmpty($this->subject->errorLog);
50+
}
51+
52+
#[Test]
53+
public function moveRecordOfNonAccessibleRecordIsDenied(): void
54+
{
55+
$recordUid = 2;
56+
$sourcePid = 5;
57+
$targetPid = 2;
58+
$this->subject->moveRecord('tt_content', $recordUid, $targetPid);
59+
self::assertStringContainsString(
60+
sprintf(
61+
'Attempt to move record tt_content:%d to pid "%d" without having permissions to update the source page (uid=%d)',
62+
$recordUid,
63+
$targetPid,
64+
$sourcePid,
65+
),
66+
$this->subject->errorLog[0]
67+
);
68+
}
69+
}

0 commit comments

Comments
 (0)