CVE-2026-47352
Description
Authenticated backend users were able to retrieve file metadata via several Backend API routes without proper permission checks, allowing access to files outside their permitted file mounts or storages. This issue affects TYPO3 CMS versions before 10.4.57, 11.0.0-11.5.51, 12.0.0-12.4.46, 13.0.0-13.4.31 and 14.0.0-14.3.3.
Affected products
2Patches
2bfe7c354168f[SECURITY] Check file permissions before showing meta data
4 files changed · +26 −5
typo3/sysext/backend/Classes/Controller/File/ImageProcessController.php+3 −0 modified@@ -42,6 +42,9 @@ public function process(ServerRequestInterface $request): ResponseInterface $processedFileId = (int)($request->getQueryParams()['id'] ?? 0); try { $processedFile = $this->imageProcessingService->process($processedFileId); + if (!$processedFile->getOriginalFile()->checkActionPermission('read')) { + return new HtmlResponse('', 403); + } return new RedirectResponse( GeneralUtility::locationHeaderUrl($processedFile->getPublicUrl() ?? '', $request)
typo3/sysext/backend/Classes/Controller/LinkController.php+17 −5 modified@@ -26,6 +26,7 @@ use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Messaging\FlashMessageQueue; use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException; +use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException; use TYPO3\CMS\Core\Resource\File; use TYPO3\CMS\Core\Resource\Folder; use TYPO3\CMS\Core\Resource\ResourceFactory; @@ -47,34 +48,45 @@ public function resourceAction(ServerRequestInterface $request): ResponseInterfa $identifier = $request->getParsedBody()['identifier'] ?? null; $resource = null; - if ($identifier) { - $resource = $this->resourceFactory->retrieveFileOrFolderObject($identifier); - } - try { + if ($identifier) { + $resource = $this->resourceFactory->retrieveFileOrFolderObject($identifier); + } if (!$resource instanceof File && !$resource instanceof Folder) { throw new \InvalidArgumentException('Resource must be a file or a folder', 1679039649); } if ($resource->getStorage()->isFallbackStorage()) { throw new InsufficientFileAccessPermissionsException('You are not allowed to access files outside your storages', 1679039650); } if ($resource instanceof File) { + if (!$resource->checkActionPermission('read')) { + throw new InsufficientFileAccessPermissionsException('You are not allowed to access this file', 1779001351); + } $parameters = [ 'type' => LinkService::TYPE_FILE, 'file' => $resource, ]; } if ($resource instanceof Folder) { + // Note: No explicit `$resource->checkActionPermission('read')` check here, as that would + // be a no-op since `ResourceStorage::getFolder()` calls `assureFolderReadPermission()` + // and throws `InsufficientFolderAccessPermissionsException` $parameters = [ 'type' => LinkService::TYPE_FOLDER, 'folder' => $resource, ]; } $link = $this->linkService->asString($parameters); + } catch (InsufficientFileAccessPermissionsException|InsufficientFolderAccessPermissionsException $exception) { + $message = match ($exception->getCode()) { + 1679039650 => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceOutsideOfStorages'), + default => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNoPermissionRead'), + }; + + return new JsonResponse($this->getResponseData(false, $message)); } catch (\Exception $exception) { $message = match ($exception->getCode()) { 1679039649 => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNotFileOrFolder'), - 1679039650 => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceOutsideOfStorages'), default => $exception->getMessage(), };
typo3/sysext/backend/Classes/Controller/Resource/ResourceController.php+3 −0 modified@@ -65,6 +65,9 @@ public function gatherInformationAction(ServerRequestInterface $request): Respon if ($resource === null) { return new JsonResponse(null, 404); } + if (!$resource->checkActionPermission('read')) { + return new JsonResponse(null, 403); + } return new JsonResponse($this->getResourceResponseData($resource)); }
typo3/sysext/backend/Resources/Private/Language/locallang_resource.xlf+3 −0 modified@@ -21,6 +21,9 @@ <trans-unit id="ajax.error.message.resourceOutsideOfStorages"> <source>Access to files outside your configured storages is not permitted.</source> </trans-unit> + <trans-unit id="ajax.error.message.resourceNoPermissionRead"> + <source>Reading this resource is not permitted.</source> + </trans-unit> <trans-unit id="ajax.error.message.resourceNoPermissionRename"> <source>Renaming this resource is not permitted.</source> </trans-unit>
17a3b7830d59[SECURITY] Check file permissions before showing meta data
3 files changed · +23 −5
typo3/sysext/backend/Classes/Controller/File/ImageProcessController.php+3 −0 modified@@ -50,6 +50,9 @@ public function process(ServerRequestInterface $request): ResponseInterface $processedFileId = (int)($request->getQueryParams()['id'] ?? 0); try { $processedFile = $this->imageProcessingService->process($processedFileId); + if (!$processedFile->getOriginalFile()->checkActionPermission('read')) { + return new HtmlResponse('', 403); + } return new RedirectResponse( GeneralUtility::locationHeaderUrl($processedFile->getPublicUrl() ?? '')
typo3/sysext/backend/Classes/Controller/LinkController.php+17 −5 modified@@ -26,6 +26,7 @@ use TYPO3\CMS\Core\Messaging\FlashMessage; use TYPO3\CMS\Core\Messaging\FlashMessageQueue; use TYPO3\CMS\Core\Resource\Exception\InsufficientFileAccessPermissionsException; +use TYPO3\CMS\Core\Resource\Exception\InsufficientFolderAccessPermissionsException; use TYPO3\CMS\Core\Resource\File; use TYPO3\CMS\Core\Resource\Folder; use TYPO3\CMS\Core\Resource\ResourceFactory; @@ -47,34 +48,45 @@ public function resourceAction(ServerRequestInterface $request): ResponseInterfa $identifier = $request->getParsedBody()['identifier'] ?? null; $resource = null; - if ($identifier) { - $resource = $this->resourceFactory->retrieveFileOrFolderObject($identifier); - } - try { + if ($identifier) { + $resource = $this->resourceFactory->retrieveFileOrFolderObject($identifier); + } if (!$resource instanceof File && !$resource instanceof Folder) { throw new \InvalidArgumentException('Resource must be a file or a folder', 1679039649); } if ($resource->getStorage()->isFallbackStorage()) { throw new InsufficientFileAccessPermissionsException('You are not allowed to access files outside your storages', 1679039650); } if ($resource instanceof File) { + if (!$resource->checkActionPermission('read')) { + throw new InsufficientFileAccessPermissionsException('You are not allowed to access this file', 1779001351); + } $parameters = [ 'type' => LinkService::TYPE_FILE, 'file' => $resource, ]; } if ($resource instanceof Folder) { + // Note: No explicit `$resource->checkActionPermission('read')` check here, as that would + // be a no-op since `ResourceStorage::getFolder()` calls `assureFolderReadPermission()` + // and throws `InsufficientFolderAccessPermissionsException` $parameters = [ 'type' => LinkService::TYPE_FOLDER, 'folder' => $resource, ]; } $link = $this->linkService->asString($parameters); + } catch (InsufficientFileAccessPermissionsException|InsufficientFolderAccessPermissionsException $exception) { + $message = match ($exception->getCode()) { + 1679039650 => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceOutsideOfStorages'), + default => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNoPermissionRead'), + }; + + return new JsonResponse($this->getResponseData(false, $message)); } catch (\Exception $exception) { $message = match ($exception->getCode()) { 1679039649 => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceNotFileOrFolder'), - 1679039650 => $this->getLanguageService()->sL('LLL:EXT:backend/Resources/Private/Language/locallang_resource.xlf:ajax.error.message.resourceOutsideOfStorages'), default => $exception->getMessage(), };
typo3/sysext/backend/Resources/Private/Language/locallang_resource.xlf+3 −0 modified@@ -19,6 +19,9 @@ <trans-unit id="ajax.error.message.resourceOutsideOfStorages"> <source>Access to files outside your configured storages is not permitted.</source> </trans-unit> + <trans-unit id="ajax.error.message.resourceNoPermissionRead"> + <source>Reading this resource is not permitted.</source> + </trans-unit> <trans-unit id="ajax.error.message.resourceNoPermissionRename"> <source>Renaming this resource is not permitted.</source> </trans-unit>
Vulnerability mechanics
Root cause
"Backend API routes did not properly check file permissions before retrieving file metadata."
Attack vector
Authenticated backend users could exploit this vulnerability by making requests to specific Backend API routes that retrieve file metadata. These routes lacked sufficient permission checks, allowing users to access metadata for files outside of their permitted file mounts or storages. The vulnerability was present in multiple versions of TYPO3 CMS.
Affected code
The vulnerability is located in the `resourceAction` method within the TYPO3 backend. The affected code paths are where file and folder objects are retrieved using `resourceFactory->retrieveFileOrFolderObject($identifier)` without adequate permission validation before proceeding to access their metadata [ref_id=1, ref_id=2].
What the fix does
The patch introduces checks for file and folder read permissions before retrieving resource metadata. Specifically, it adds calls to `checkActionPermission('read')` for files and ensures folder read permissions are asserted for folders. This prevents unauthorized access to file metadata by ensuring that only users with appropriate permissions can retrieve the information, thereby closing the vulnerability [patch_id=5349014, patch_id=5349013].
Preconditions
- authThe attacker must be an authenticated backend user.
Generated on Jun 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
3News mentions
1- TYPO3 CMS: Thirteen Backend Vulnerabilities Disclosed on June 9, 2026Vypr Intelligence · Jun 9, 2026