Skip to content

Commit 932fbb9

Browse files
eliashaeusslerohader
authored andcommitted
[SECURITY] Check record/file access when adding records to clipboard
TYPO3's clipboard functionality is able to store arbitrary records and files to further copy or move them around. While the copy and move operations are already covered by appropriate permission checks, the actual clipboard insertion step failed to properly calculate actual permissions. This allowed an attacker to insert arbitrary records and files into the clipboard, which in turn allowed them to gather information about the stored records/files. This changes implements proper permission checks to avoid the described scenario. Whenever records and files are inserted to the clipboard, they are validated against existing read permissions for the current backend user. If the user does not have proper permissions, the requested records and files are denied for clipboard insertion. Resolves: #109364 Releases: main, 14.3, 13.4 Change-Id: Id4db3edabeddd6466e69fdf8bab1a52b42668d91 Security-Bulletin: TYPO3-CORE-SA-2026-014 Security-References: CVE-2026-47351 Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/94419 Reviewed-by: Oliver Hader <oliver.hader@typo3.org> Tested-by: Oliver Hader <oliver.hader@typo3.org>
1 parent caa6b44 commit 932fbb9

1 file changed

Lines changed: 28 additions & 13 deletions

File tree

typo3/sysext/backend/Classes/Clipboard/Clipboard.php

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@
3030
use TYPO3\CMS\Core\Imaging\IconFactory;
3131
use TYPO3\CMS\Core\Imaging\IconSize;
3232
use TYPO3\CMS\Core\Localization\LanguageService;
33+
use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException;
3334
use TYPO3\CMS\Core\Resource\Exception\ResourceDoesNotExistException;
3435
use TYPO3\CMS\Core\Resource\File;
3536
use TYPO3\CMS\Core\Resource\Folder;
3637
use TYPO3\CMS\Core\Resource\ProcessedFile;
3738
use TYPO3\CMS\Core\Resource\ResourceFactory;
3839
use TYPO3\CMS\Core\Schema\Capability\TcaSchemaCapability;
3940
use TYPO3\CMS\Core\Schema\TcaSchemaFactory;
41+
use TYPO3\CMS\Core\Type\Bitmask\Permission;
4042
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
4143
use TYPO3\CMS\Core\Utility\GeneralUtility;
4244
use TYPO3\CMS\Core\Utility\MathUtility;
@@ -662,21 +664,34 @@ public function cleanCurrent(): void
662664

663665
foreach ($this->clipData[$this->current]['el'] as $reference => $value) {
664666
[$table, $uid] = explode('|', $reference);
665-
if ($table !== '_FILE') {
666-
if (!$value || !is_array(BackendUtility::getRecord($table, (int)$uid, 'uid'))) {
667-
unset($this->clipData[$this->current]['el'][$reference]);
668-
$this->changed = true;
669-
}
670-
} elseif (!$value) {
671-
unset($this->clipData[$this->current]['el'][$reference]);
672-
$this->changed = true;
673-
} else {
667+
$unset = false;
668+
669+
if (!$value) {
670+
$unset = true;
671+
} elseif ($table === '_FILE') {
674672
try {
675-
$this->resourceFactory->retrieveFileOrFolderObject($value);
676-
} catch (ResourceDoesNotExistException $e) {
677-
// The file has been deleted in the meantime, so just remove it silently
678-
unset($this->clipData[$this->current]['el'][$reference]);
673+
$fileOrFolder = $this->resourceFactory->retrieveFileOrFolderObject($value);
674+
675+
if (($fileOrFolder instanceof File || $fileOrFolder instanceof Folder)
676+
&& !$fileOrFolder->checkActionPermission('read')
677+
) {
678+
$unset = true;
679+
}
680+
} catch (InsufficientFolderAccessPermissionsException|ResourceDoesNotExistException) {
681+
// If either the file has been deleted in the meantime or the user lacks permissions
682+
// for the folder, we just remove the clipboard entry silently
683+
$unset = true;
679684
}
685+
} elseif (!is_array($row = BackendUtility::getRecord($table, (int)$uid, ['uid', 'pid']))
686+
|| !$this->getBackendUser()->check('tables_select', $table)
687+
|| !is_array($page = BackendUtility::getRecord('pages', (int)($table === 'pages' ? $row['uid'] : $row['pid'])))
688+
|| !$this->getBackendUser()->doesUserHaveAccess($page, Permission::PAGE_SHOW)
689+
) {
690+
$unset = true;
691+
}
692+
693+
if ($unset) {
694+
$this->removeElement($reference);
680695
}
681696
}
682697
}

0 commit comments

Comments
 (0)