CVE-2021-43836 (PHP, published 2021-12-15T20:15Z)
Description: value: Sulu is an open-source PHP content management system based on the Symfony framework. In affected versions an attacker can read arbitrary local files via a PHP file include. In a default configuration this also leads to remote code execution. The problem is patched with the Versions 1.6.44, 2.2.18, 2.3.8, 2.4.0. For users unable to upgrade overwrite the service `sulu_route.generator.expression_token_provider` and wrap the translator before passing it to the expression language.
Severity: MEDIUM (CVSS v3 base score: 8.8)
Weakness: CWE-22 \u2014 Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
The product uses external input to construct a pathname that is intended to identify a file or directory that is located underneath a restricted parent directory, but the product does not properly neutralize special elements within the pathname that can cause the pathname to resolve to a location that is outside of the restricted directory.
Repository: https://github.com/sulu/sulu
Files changed:
src/Sulu/Bundle/RouteBundle/Generator/SymfonyExpressionTokenProvider.php
src/Sulu/Bundle/RouteBundle/Generator/TranslatorWrapper.php
src/Sulu/Bundle/RouteBundle/Tests/Unit/Generator/SymfonyExpressionTokenProviderTest.php
Commit message: Merge pull request from GHSA-vx6j-pjrh-vgjh



Vulnerable code:
            $result = $this->expressionLanguage->evaluate($name, ['object' => $entity, 'translator' => $this->translator]);
        $translator->trans('test-key')->willReturn('TEST');

Fixed code:
            $result = $this->expressionLanguage->evaluate($name, [
                'object' => $entity,
                'translator' => new TranslatorWrapper($this->translator),
            ]);
<?php

namespace Sulu\Bundle\RouteBundle\Generator;

use Symfony\Component\Translation\TranslatorInterface;

/**
 * @internal
 */
class TranslatorWrapper implements TranslatorInterface
{
    /**
     * @var TranslatorInterface
     */
    private $translator;

    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }

    public function trans($id, array $parameters = [], $domain = null, $locale = null)
    {
        return $this->translator->trans($id, $parameters, $domain, $locale);
    }

    public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null)
    {
        return $this->translator->transChoice($id, $number, $parameters, $domain, $locale);
    }

    public function setLocale($locale)
    {
        throw new \Exception('Not supported.');
    }

    public function getLocale()
    {
        return $this->translator->getLocale();
    }
}
use Prophecy\Argument;
use Symfony\Component\Translation\Translator;
        $translator->trans('test-key', Argument::cetera())->willReturn('TEST');
    public function testResolveTranslationAddResource()
    {
        $this->setExpectedException(CannotEvaluateTokenException::class);

        $translator = $this->prophesize(Translator::class);
        $translator->getLocale()->willReturn('de');
        $translator->setLocale('de')->shouldBeCalled();
        $entity = $this->prophesize(RoutableInterface::class);
        $entity->getLocale()->willReturn('en');

        $entity->getLocale = function() {
            return 'en';
        };
        $provider = new SymfonyExpressionTokenProvider($translator->reveal());
        $provider->provide($entity, 'translator.addResource("php", "/test.php")');
    }