VYPR
Moderate severityNVD Advisory· Published Oct 31, 2023· Updated Sep 5, 2024

Pimcore Admin Classic Bundle Cross-site Scripting (XSS) in PDF previews

CVE-2023-46722

Description

The Pimcore Admin Classic Bundle provides a backend UI for Pimcore. Prior to version 1.2.0, a cross-site scripting vulnerability has the potential to steal a user's cookie and gain unauthorized access to that user's account through the stolen cookie or redirect users to other malicious sites. Users should upgrade to version 1.2.0 to receive a patch or, as a workaround, apply the patch manually.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
pimcore/admin-ui-classic-bundlePackagist
< 1.2.01.2.0

Affected products

1

Patches

2
19fda2e86557

[Improvement]: Add sanitizing pdf (#301)

5 files changed · +156 7
  • src/Controller/Admin/Asset/AssetController.php+48 6 modified
    @@ -33,6 +33,7 @@
     use Pimcore\Loader\ImplementationLoader\Exception\UnsupportedException;
     use Pimcore\Logger;
     use Pimcore\Messenger\AssetPreviewImageMessage;
    +use Pimcore\Messenger\AssetUpdateTasksMessage;
     use Pimcore\Model;
     use Pimcore\Model\Asset;
     use Pimcore\Model\DataObject\ClassDefinition\Data\ManyToManyRelation;
    @@ -984,6 +985,13 @@ public function showVersionAction(Request $request): Response
                 throw $this->createAccessDeniedHttpException('Permission denied, version id [' . $id . ']');
             }
     
    +        if ($asset->getMimeType() === 'application/pdf') {
    +            $scanResponse = $this->getResponseByScanStatus($asset, false);
    +            if ($scanResponse) {
    +                return $scanResponse;
    +            }
    +        }
    +
             $loader = \Pimcore::getContainer()->get('pimcore.implementation_loader.asset.metadata.data');
     
             return $this->render(
    @@ -1487,12 +1495,11 @@ protected function addThumbnailCacheHeaders(Response $response): void
     
         /**
          * @Route("/get-preview-document", name="pimcore_admin_asset_getpreviewdocument", methods={"GET"})
    -     *
    -     * @param Request $request
    -     *
    -     * @return StreamedResponse
          */
    -    public function getPreviewDocumentAction(Request $request): StreamedResponse
    +    public function getPreviewDocumentAction(
    +        Request $request,
    +        TranslatorInterface $translator
    +    ): StreamedResponse|Response
         {
             $asset = Asset\Document::getById((int) $request->get('id'));
     
    @@ -1501,6 +1508,13 @@ public function getPreviewDocumentAction(Request $request): StreamedResponse
             }
     
             if ($asset->isAllowed('view')) {
    +            if ($asset->getMimeType() === 'application/pdf') {
    +                $scanResponse = $this->getResponseByScanStatus($asset);
    +                if ($scanResponse) {
    +                    return $scanResponse;
    +                }
    +            }
    +
                 $stream = $this->getDocumentPreviewPdf($asset);
                 if ($stream) {
                     return new StreamedResponse(function () use ($stream) {
    @@ -1516,6 +1530,29 @@ public function getPreviewDocumentAction(Request $request): StreamedResponse
             }
         }
     
    +    private function getResponseByScanStatus(Asset\Document $asset, bool $processBackground = true) :?Response
    +    {
    +        if (!Config::getSystemConfiguration('assets')['document']['scan_pdf']) {
    +            return null;
    +        }
    +
    +        $scanStatus = $asset->getScanStatus();
    +        if ($scanStatus === null) {
    +            $scanStatus = Asset\Enum\PdfScanStatus::IN_PROGRESS;
    +            if ($processBackground) {
    +                \Pimcore::getContainer()->get('messenger.bus.pimcore-core')->dispatch(
    +                    new AssetUpdateTasksMessage($asset->getId())
    +                );
    +            }
    +        }
    +
    +        return match($scanStatus) {
    +            Asset\Enum\PdfScanStatus::IN_PROGRESS => $this->render('@PimcoreAdmin/admin/asset/get_preview_pdf_in_progress.html.twig'),
    +            Asset\Enum\PdfScanStatus::UNSAFE => $this->render('@PimcoreAdmin/admin/asset/get_preview_pdf_unsafe.html.twig'),
    +            default => null,
    +        };
    +    }
    +
         /**
          * @param Asset\Document $asset
          *
    @@ -1529,7 +1566,12 @@ protected function getDocumentPreviewPdf(Asset\Document $asset)
                 $stream = $asset->getStream();
             }
     
    -        if (!$stream && $asset->getPageCount() && \Pimcore\Document::isAvailable() && \Pimcore\Document::isFileTypeSupported($asset->getFilename())) {
    +        if (
    +            !$stream &&
    +            $asset->getPageCount() &&
    +            \Pimcore\Document::isAvailable() &&
    +            \Pimcore\Document::isFileTypeSupported($asset->getFilename())
    +        ) {
                 try {
                     $document = \Pimcore\Document::getInstance();
                     $stream = $document->getPdf($asset);
    
  • templates/admin/asset/get_preview_pdf_in_progress.html.twig+51 0 added
    @@ -0,0 +1,51 @@
    +<!DOCTYPE html>
    +<html>
    +<head>
    +    <meta charset="UTF-8">
    +
    +    <style>
    +
    +        /* hide from ie on mac \*/
    +        html {
    +            height: 100%;
    +            overflow: hidden;
    +        }
    +        /* end hide */
    +
    +        body {
    +            height: 100%;
    +            margin: 0;
    +            padding: 0;
    +            background: #EEE;
    +        }
    +
    +        #container {
    +            text-align: center;
    +            position: absolute;
    +            top:50%;
    +            margin-top: -200px;
    +            width: 100%;
    +        }
    +
    +        #message {
    +            margin-left: 8px;
    +        }
    +
    +    </style>
    +
    +    <script {{ pimcore_csp.getNonceHtmlAttribute()|raw }}>
    +        window.setTimeout(() => {
    +            window.location.reload();
    +        }, 5000)
    +    </script>
    +</head>
    +
    +<body>
    +
    +<div id="container">
    +    <span id="message">{{ 'pdf_scan_in_progress'|trans([], 'admin') }}</span>
    +</div>
    +
    +
    +</body>
    +</html>
    
  • templates/admin/asset/get_preview_pdf_unsafe.html.twig+54 0 added
    @@ -0,0 +1,54 @@
    +<!DOCTYPE html>
    +<html>
    +<head>
    +    <meta charset="UTF-8">
    +
    +    <style>
    +
    +        /* hide from ie on mac \*/
    +        html {
    +            height: 100%;
    +            overflow: hidden;
    +        }
    +        /* end hide */
    +
    +        body {
    +            height: 100%;
    +            margin: 0;
    +            padding: 0;
    +            background: #EEE;
    +        }
    +
    +        #container {
    +            text-align: center;
    +            position: absolute;
    +            top:50%;
    +            margin-top: -200px;
    +            width: 100%;
    +        }
    +
    +        #warning {
    +            position: relative;
    +            width: 40px;
    +            height: 40px;
    +            top: 13px;
    +        }
    +
    +        #message {
    +            margin-left: 8px;
    +        }
    +
    +    </style>
    +
    +</head>
    +
    +<body>
    +
    +<div id="container">
    +    <img alt="warning" id="warning" src="/bundles/pimcoreadmin/img/flat-color-icons/overlay-error.svg" />
    +    <span id="message">{{ 'pdf_js_unsafe'|trans([], 'admin') }}</span>
    +</div>
    +
    +
    +</body>
    +</html>
    
  • templates/admin/asset/show_version_document.html.twig+1 1 modified
    @@ -1,7 +1,7 @@
     {% if asset.getMimeType() == 'application/pdf' %}
         {% set tempFile = asset.getTemporaryFile() %}
         {% set dataUri = pimcore_asset_version_preview(tempFile) %}
    -    
    +
         <div style="display: flex; width: 100%; height: 100%; flex-direction: column; overflow: hidden;">
             <iframe src="{{ dataUri }}" frameborder="0" style="flex-grow: 1; border: none; margin: 0; padding: 0;"></iframe>
         </div>
    
  • translations/admin.en.yaml+2 0 modified
    @@ -988,3 +988,5 @@ allow_asset_inline_download: Allow inline download
     system_appearance_settings: 'Appearance & Branding'
     male: Male
     female: Female
    +pdf_js_unsafe: This PDF file contains JavaScript. If you want to view it, please download and open it in your local PDF viewer.
    +pdf_scan_in_progress: 'Preview not available: PDF is being scanned. This may take a while.'
    
757375677dc8

Implement Asset Sanitizer Queue & Preview Check (#16053)

https://github.com/pimcore/pimcorerobertSt7Oct 9, 2023via ghsa
7 files changed · +93 0
  • bundles/CoreBundle/src/DependencyInjection/Configuration.php+4 0 modified
    @@ -553,6 +553,10 @@ private function addAssetNode(ArrayNodeDefinition $rootNode): void
                                     ->defaultTrue()
                                     ->info('Process text for Asset documents (e.g. used by backend search).')
                                 ->end()
    +                            ->booleanNode('scan_pdf')
    +                                ->defaultTrue()
    +                                ->info('Scan PDF documents for unsafe JavaScript.')
    +                            ->end()
                             ->end()
                         ->end()
                         ->arrayNode('versions')
    
  • doc/04_Assets/README.md+1 0 modified
    @@ -28,6 +28,7 @@ pimcore:
                     enabled: false #disable generating thumbnail for asset documents
                 process_page_count: false #disable processing page count
                 process_text: false #disable processing text extraction
    +            scan_pdf: false #disable scanning PDF documents for unsafe JavaScript.
     ```
     
     The sub chapters of this chapter provide insight into details for
    
  • doc/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md+2 0 modified
    @@ -20,6 +20,8 @@ pimcore:
                     enabled: false #disable generating thumbnail for asset documents
                 process_page_count: false #disable processing page count
                 process_text: false #disable processing text extraction
    +            scan_pdf: false #disable scanning PDF documents for unsafe JavaScript.
    +
     ```
     - [Elements] Properties are now only updated in the database with dirty state (when calling `setProperties` or `setProperty`).
     - `Pimcore\Helper\CsvFormulaFormatter` has been deprecated. Use `League\Csv\EscapeFormula` instead.
    
  • lib/Messenger/Handler/AssetUpdateTasksHandler.php+4 0 modified
    @@ -62,6 +62,10 @@ private function saveAsset(Asset $asset): void
     
         private function processDocument(Asset\Document $asset): void
         {
    +        if ($asset->getMimeType() === 'application/pdf' && $asset->checkIfPdfContainsJS()) {
    +            $asset->save(['versionNote' => 'PDF scan result']);
    +        }
    +
             $pageCount = $asset->getCustomSetting('document_page_count');
             if (!$pageCount || $pageCount === 'failed') {
                 if ($asset->processPageCount()) {
    
  • models/Asset/Document.php+54 0 modified
    @@ -26,6 +26,8 @@
      */
     class Document extends Model\Asset
     {
    +    public const CUSTOM_SETTING_PDF_SCAN_STATUS = 'document_pdf_scan_status';
    +
         protected string $type = 'document';
     
         protected function update(array $params = []): void
    @@ -163,6 +165,53 @@ public function getText(int $page = null): ?string
             return null;
         }
     
    +    public function checkIfPdfContainsJS(): bool
    +    {
    +        if (!$this->isPdfScanningEnabled()) {
    +           return false;
    +        }
    +
    +        $this->setCustomSetting(
    +            self::CUSTOM_SETTING_PDF_SCAN_STATUS,
    +            Model\Asset\Enum\PdfScanStatus::IN_PROGRESS->value
    +        );
    +
    +        $chunkSize = 1024;
    +        $filePointer = $this->getStream();
    +
    +        $tagLength = strlen('/JS');
    +
    +        while ($chunk = fread($filePointer, $chunkSize)) {
    +            if (strlen($chunk) <= $tagLength) {
    +                break;
    +            }
    +
    +            if (str_contains($chunk, '/JS') || str_contains($chunk, '/JavaScript')) {
    +                $this->setCustomSetting(
    +                    self::CUSTOM_SETTING_PDF_SCAN_STATUS,
    +                    Model\Asset\Enum\PdfScanStatus::UNSAFE->value
    +                );
    +                return true;
    +            }
    +        }
    +
    +        $this->setCustomSetting(
    +            self::CUSTOM_SETTING_PDF_SCAN_STATUS,
    +            Model\Asset\Enum\PdfScanStatus::SAFE->value
    +        );
    +
    +        return true;
    +    }
    +
    +    public function getScanStatus(): ?Model\Asset\Enum\PdfScanStatus
    +    {
    +        if ($scanStatus = $this->getCustomSetting(self::CUSTOM_SETTING_PDF_SCAN_STATUS)) {
    +            return Model\Asset\Enum\PdfScanStatus::tryFrom($scanStatus);
    +        }
    +
    +        return null;
    +    }
    +
         private function isThumbnailsEnabled(): bool
         {
             return Config::getSystemConfiguration('assets')['document']['thumbnails']['enabled'];
    @@ -177,4 +226,9 @@ private function isTextProcessingEnabled(): bool
         {
             return Config::getSystemConfiguration('assets')['document']['process_text'];
         }
    +
    +    private function isPdfScanningEnabled(): bool
    +    {
    +        return Config::getSystemConfiguration('assets')['document']['scan_pdf'];
    +    }
     }
    
  • models/Asset/Enum/PdfScanStatus.php+24 0 added
    @@ -0,0 +1,24 @@
    +<?php
    +declare(strict_types=1);
    +
    +/**
    + * Pimcore
    + *
    + * This source file is available under two different licenses:
    + * - GNU General Public License version 3 (GPLv3)
    + * - Pimcore Commercial License (PCL)
    + * Full copyright and license information is available in
    + * LICENSE.md which is distributed with this source code.
    + *
    + *  @copyright  Copyright (c) Pimcore GmbH (http://www.pimcore.org)
    + *  @license    http://www.pimcore.org/license     GPLv3 and PCL
    + */
    +
    +namespace Pimcore\Model\Asset\Enum;
    +
    +enum PdfScanStatus: string
    +{
    +    case SAFE = 'safe';
    +    case UNSAFE = 'unsafe';
    +    case IN_PROGRESS = 'inProgress';
    +}
    
  • models/Element/Service.php+4 0 modified
    @@ -731,6 +731,10 @@ public static function renewReferences(mixed $data, bool $initial = true, string
                 return $data;
             }
             if (is_object($data)) {
    +            if ($data instanceof \UnitEnum) {
    +                return $data;
    +            }
    +
                 if ($data instanceof ElementInterface && !$initial) {
                     return self::getElementById(self::getElementType($data), $data->getId());
                 }
    

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

5

News mentions

0

No linked articles in our index yet.