CVE-2022-0565 (PHP, published 2022-02-14T12:15Z)
Description: value: Cross-site Scripting in Packagist pimcore/pimcore prior to 10.3.1.


Severity: MEDIUM (CVSS v3 base score: 6.4)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/pimcore/pimcore
Files changed:
bundles/AdminBundle/Controller/Admin/SettingsController.php
bundles/CoreBundle/EventListener/AssetSanitizationListener.php
bundles/CoreBundle/Resources/config/event_listeners.yaml
composer.json
Commit message: Svg sanitization (#11386)

* setting up the svg saniziter on logo and assets upload

* more detailed exception message

* changed to mime type check instead of file extension

* adding the sanitization to "Upload new version"

* refactor to sanitize on preAdd/preUpdate, rollback AssetController.php

* fix resource|string, null given on mime_content_type

* using symfony mime component + small tweaks

* avoiding save without changes case

* tweak when checking if is image type

Vulnerable code:
        if ($fileExt === 'svg' && stripos(file_get_contents($_FILES['Filedata']['tmp_name']), '<script')) {
            throw new \Exception('Scripts in SVG files are not supported');
        }
        $storage->writeStream(self::CUSTOM_LOGO_PATH, fopen($_FILES['Filedata']['tmp_name'], 'rb'));

Fixed code:
use Symfony\Component\Mime\MimeTypes;
use enshrined\svgSanitize\Sanitizer;

        $sourcePath = $_FILES['Filedata']['tmp_name'];

        $fileMimeType = MimeTypes::getDefault()->guessMimeType($sourcePath);

        if ($fileMimeType === 'image/svg+xml') {
            $fileContent = file_get_contents($sourcePath);

            $sanitizer = new Sanitizer();
            $sanitizedFileContent = $sanitizer->sanitize($fileContent);
            if ($sanitizedFileContent) {
                $storage->write(self::CUSTOM_LOGO_PATH, $sanitizedFileContent);
            }else{
                throw new \Exception('SVG Sanitization failed, probably due badly formatted XML. Filename:'.$sourcePath);
            }
        }else {
            $storage->writeStream(self::CUSTOM_LOGO_PATH, fopen($sourcePath, 'rb'));
        }
<?php

/**
 * 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\Bundle\CoreBundle\EventListener;


use Pimcore\Event\AssetEvents;
use Pimcore\Event\Model\ElementEventInterface;
use Pimcore\Model\Asset;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use enshrined\svgSanitize\Sanitizer;
use Symfony\Component\Mime\MimeTypes;

/**
 * @internal
 */
class AssetSanitizationListener implements EventSubscriberInterface
{
    public static function getSubscribedEvents()
    {
        return [
            AssetEvents::PRE_ADD => 'sanitizeAsset',
            AssetEvents::PRE_UPDATE => 'sanitizeAsset',
        ];
    }

    /**
     * @param ElementEventInterface $e
     */
    public function sanitizeAsset(ElementEventInterface $e)
    {
        $element = $e->getElement();

        if ($element instanceof Asset\Image && $element->getDataChanged()) {
            $assetStream = $element->getStream();

            if (isset($assetStream)) {
                $streamMetaData = stream_get_meta_data($assetStream);
                $mime = MimeTypes::getDefault()->guessMimeType($streamMetaData['uri']);

                if ($mime === 'image/svg+xml') {
                    $sanitizedData = $this->sanitizeSVG(stream_get_contents($assetStream));
                    $element->setData($sanitizedData);
                }
            }
        }
    }

    /**
     * @param string $fileContent
     *
     * @return string
     *
     * @throws \Exception
     */

    protected function sanitizeSVG(string $fileContent)
    {
        $sanitizer = new Sanitizer();
        $sanitizedFileContent = $sanitizer->sanitize($fileContent);

        if (!$sanitizedFileContent) {
            throw new \Exception('SVG Sanitization failed, probably due badly formatted XML.');
        }

        return $sanitizedFileContent;
    }
}

    Pimcore\Bundle\CoreBundle\EventListener\AssetSanitizationListener: ~
    "enshrined/svg-sanitize": "^0.14.1",