Full Path Disclosure via re-export document in pimcore/admin-ui-classic-bundle
Description
The Pimcore Admin Classic Bundle provides a Backend UI for Pimcore. Full Path Disclosure (FPD) vulnerabilities enable the attacker to see the path to the webroot/file. e.g.: /home/omg/htdocs/file/. Certain vulnerabilities, such as using the load_file() (within a SQL Injection) query to view the page source, require the attacker to have the full path to the file they wish to view. In the case of pimcore, the fopen() function here doesn't have an error handle when the file doesn't exist on the server so the server response raises the full path "fopen(/var/www/html/var/tmp/export-{ uniqe id}.csv)". This issue has been patched in commit 10d178ef771 which has been included in release version 1.2.1. Users are advised to upgrade. There are no known workarounds for this vulnerability.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
pimcore/admin-ui-classic-bundlePackagist | < 1.2.1 | 1.2.1 |
Affected products
1- Range: < 1.2.1
Patches
110d178ef7710Grid Export - Catch unable to read file exception (#342)
2 files changed · +95 −74
src/Controller/Admin/Asset/AssetHelperController.php+32 −26 modified@@ -26,8 +26,8 @@ use Pimcore\Bundle\AdminBundle\Model\GridConfigShare; use Pimcore\Bundle\AdminBundle\Tool; use Pimcore\Db; +use Pimcore\File; use Pimcore\Loader\ImplementationLoader\Exception\UnsupportedException; -use Pimcore\Localization\LocaleServiceInterface; use Pimcore\Logger; use Pimcore\Model\Asset; use Pimcore\Model\Element; @@ -722,17 +722,13 @@ public function getExportJobsAction(Request $request, GridHelperService $gridHel /** * @Route("/do-export", name="pimcore_admin_asset_assethelper_doexport", methods={"POST"}) * - * @param Request $request - * @param LocaleServiceInterface $localeService - * - * @return JsonResponse + * @throws FilesystemException */ - public function doExportAction(Request $request, LocaleServiceInterface $localeService): JsonResponse + public function doExportAction(Request $request): JsonResponse { - $fileHandle = \Pimcore\File::getValidFilename($request->get('fileHandle')); + $fileHandle = File::getValidFilename($request->get('fileHandle')); $ids = $request->get('ids'); - $settings = $request->get('settings'); - $settings = json_decode($settings, true); + $settings = json_decode($request->get('settings'), true); $delimiter = $settings['delimiter'] ?? ';'; $language = str_replace('default', '', $request->get('language')); @@ -752,27 +748,37 @@ public function doExportAction(Request $request, LocaleServiceInterface $localeS $csv = $this->getCsvData($request, $language, $list, $fields, $addTitles); - $storage = Storage::get('temp'); - $csvFile = $this->getCsvFile($fileHandle); + try { + $storage = Storage::get('temp'); + $csvFile = $this->getCsvFile($fileHandle); - $fileStream = $storage->readStream($csvFile); + $fileStream = $storage->readStream($csvFile); - $temp = tmpfile(); - stream_copy_to_stream($fileStream, $temp, null, 0); + $temp = tmpfile(); + stream_copy_to_stream($fileStream, $temp, null, 0); - $firstLine = true; - foreach ($csv as $line) { - if ($addTitles && $firstLine) { - $firstLine = false; - $line = implode($delimiter, $line) . "\r\n"; - fwrite($temp, $line); - } else { - fwrite($temp, implode($delimiter, array_map([$this, 'encodeFunc'], $line)) . "\r\n"); + $firstLine = true; + foreach ($csv as $line) { + if ($addTitles && $firstLine) { + $firstLine = false; + $line = implode($delimiter, $line) . "\r\n"; + fwrite($temp, $line); + } else { + fwrite($temp, implode($delimiter, array_map([$this, 'encodeFunc'], $line)) . "\r\n"); + } } + $storage->writeStream($csvFile, $temp); + } catch (UnableToReadFile $exception) { + Logger::err($exception->getMessage()); + + return $this->adminJson( + [ + 'success' => false, + 'message' => sprintf('export file not found: %s', $fileHandle) + ] + ); } - $storage->writeStream($csvFile, $temp); - return $this->adminJson(['success' => true]); } @@ -860,7 +866,7 @@ protected function getCsvFile(string $fileHandle): string public function downloadCsvFileAction(Request $request): Response { $storage = Storage::get('temp'); - $fileHandle = \Pimcore\File::getValidFilename($request->get('fileHandle')); + $fileHandle = File::getValidFilename($request->get('fileHandle')); $csvFile = $this->getCsvFile($fileHandle); try { @@ -893,7 +899,7 @@ public function downloadCsvFileAction(Request $request): Response public function downloadXlsxFileAction(Request $request, GridHelperService $gridHelperService): BinaryFileResponse { $storage = Storage::get('temp'); - $fileHandle = \Pimcore\File::getValidFilename($request->get('fileHandle')); + $fileHandle = File::getValidFilename($request->get('fileHandle')); $csvFile = $this->getCsvFile($fileHandle); try {
src/Controller/Admin/DataObject/DataObjectHelperController.php+63 −48 modified@@ -26,9 +26,11 @@ use Pimcore\Bundle\AdminBundle\Model\GridConfigShare; use Pimcore\Config; use Pimcore\Db; +use Pimcore\File; use Pimcore\Localization\LocaleServiceInterface; use Pimcore\Logger; use Pimcore\Model\DataObject; +use Pimcore\Model\DataObject\Listing; use Pimcore\Model\User; use Pimcore\Security\SecurityHelper; use Pimcore\Tool; @@ -1283,20 +1285,17 @@ public function getExportJobsAction(Request $request, GridHelperService $gridHel /** * @Route("/do-export", name="doexport", methods={"POST"}) * - * @param Request $request - * @param LocaleServiceInterface $localeService - * @param EventDispatcherInterface $eventDispatcher - * - * @return JsonResponse - * - * @throws \Exception + * @throws \Exception|FilesystemException */ - public function doExportAction(Request $request, LocaleServiceInterface $localeService, EventDispatcherInterface $eventDispatcher): JsonResponse + public function doExportAction( + Request $request, + LocaleServiceInterface $localeService, + EventDispatcherInterface $eventDispatcher + ): JsonResponse { - $fileHandle = \Pimcore\File::getValidFilename($request->get('fileHandle')); + $fileHandle = File::getValidFilename($request->get('fileHandle')); $ids = $request->get('ids'); - $settings = $request->get('settings'); - $settings = json_decode($settings, true); + $settings = json_decode($request->get('settings'), true); $delimiter = $settings['delimiter'] ?? ';'; $header = $settings['header'] ?? 'title'; @@ -1308,13 +1307,13 @@ public function doExportAction(Request $request, LocaleServiceInterface $localeS $class = DataObject\ClassDefinition::getById($request->get('classId')); if (!$class) { - throw new \Exception('No class definition found'); + throw new \InvalidArgumentException('No class definition found'); } $className = $class->getName(); $listClass = '\\Pimcore\\Model\\DataObject\\' . ucfirst($className) . '\\Listing'; - /** @var \Pimcore\Model\DataObject\Listing $list */ + /** @var Listing $list */ $list = new $listClass(); $quotedIds = []; @@ -1340,56 +1339,72 @@ public function doExportAction(Request $request, LocaleServiceInterface $localeS $requestedLanguage = $this->extractLanguage($request); - $contextFromRequest = $request->get('context'); - if ($contextFromRequest) { - $contextFromRequest = json_decode($contextFromRequest, true); - } - $context = [ 'source' => 'pimcore-export', ]; - if (is_array($contextFromRequest)) { + $contextFromRequest = $request->get('context'); + if ($contextFromRequest) { + $contextFromRequest = json_decode($contextFromRequest, true); $context = array_merge($context, $contextFromRequest); } - $csv = DataObject\Service::getCsvData($requestedLanguage, $localeService, $list, $fields, $header, $addTitles, $context); + $csv = DataObject\Service::getCsvData( + $requestedLanguage, + $localeService, + $list, + $fields, + $header, + $addTitles, + $context + ); - $storage = Storage::get('temp'); - $csvFile = $this->getCsvFile($fileHandle); - - $fileStream = $storage->readStream($csvFile); - - $temp = tmpfile(); - stream_copy_to_stream($fileStream, $temp, null, 0); - - $firstLine = true; + try { + $storage = Storage::get('temp'); + $csvFile = $this->getCsvFile($fileHandle); - if ($request->get('initial') && $header === 'no_header') { - array_shift($csv); - $firstLine = false; - } + $fileStream = $storage->readStream($csvFile); - $lineCount = count($csv); + $temp = tmpfile(); + stream_copy_to_stream($fileStream, $temp, null, 0); - if (!$addTitles && $lineCount > 0) { - fwrite($temp, "\r\n"); - } + $firstLine = true; - for ($i = 0; $i < $lineCount; $i++) { - $line = $csv[$i]; - if ($addTitles && $firstLine) { + if ($request->get('initial') && $header === 'no_header') { + array_shift($csv); $firstLine = false; - $line = implode($delimiter, $line); - fwrite($temp, $line); - } else { - fwrite($temp, implode($delimiter, array_map([$this, 'encodeFunc'], $line))); } - if ($i < $lineCount - 1) { + + $lineCount = count($csv); + + if (!$addTitles && $lineCount > 0) { fwrite($temp, "\r\n"); } + + for ($i = 0; $i < $lineCount; $i++) { + $line = $csv[$i]; + if ($addTitles && $firstLine) { + $firstLine = false; + $line = implode($delimiter, $line); + fwrite($temp, $line); + } else { + fwrite($temp, implode($delimiter, array_map([$this, 'encodeFunc'], $line))); + } + if ($i < $lineCount - 1) { + fwrite($temp, "\r\n"); + } + } + $storage->writeStream($csvFile, $temp); + } catch (UnableToReadFile $exception) { + Logger::err($exception->getMessage()); + + return $this->adminJson( + [ + 'success' => false, + 'message' => sprintf('export file not found: %s', $fileHandle) + ] + ); } - $storage->writeStream($csvFile, $temp); return $this->adminJson(['success' => true]); } @@ -1412,7 +1427,7 @@ public function encodeFunc(string $value): string public function downloadCsvFileAction(Request $request): Response { $storage = Storage::get('temp'); - $fileHandle = \Pimcore\File::getValidFilename($request->get('fileHandle')); + $fileHandle = File::getValidFilename($request->get('fileHandle')); $csvFile = $this->getCsvFile($fileHandle); try { @@ -1445,7 +1460,7 @@ public function downloadCsvFileAction(Request $request): Response public function downloadXlsxFileAction(Request $request, GridHelperService $gridHelperService): BinaryFileResponse { $storage = Storage::get('temp'); - $fileHandle = \Pimcore\File::getValidFilename($request->get('fileHandle')); + $fileHandle = File::getValidFilename($request->get('fileHandle')); $csvFile = $this->getCsvFile($fileHandle); try {
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-c8hj-w239-5gvfghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-47636ghsaADVISORY
- github.com/pimcore/admin-ui-classic-bundle/commit/10d178ef771097604a256c1192b098af9ec57a87ghsax_refsource_MISCWEB
- github.com/pimcore/admin-ui-classic-bundle/security/advisories/GHSA-c8hj-w239-5gvfghsax_refsource_CONFIRMWEB
- huntr.com/bounties/4af4db18-9fd4-43e9-8bc6-c88aaf76839cghsaWEB
- huntr.com/bounties/4af4db18-9fd4-43e9-8bc6-c88aaf76839c/mitrex_refsource_MISC
News mentions
0No linked articles in our index yet.