VYPR
High severityNVD Advisory· Published Aug 8, 2024· Updated Aug 8, 2024

Shopware vulnerable to Server Side Template Injection in Twig using deprecation silence tag

CVE-2024-42355

Description

Shopware, an open ecommerce platform, has a new Twig Tag sw_silent_feature_call which silences deprecation messages while triggered in this tag. Prior to versions 6.6.5.1 and 6.5.8.13, it accepts as parameter a string the feature flag name to silence, but this parameter is not escaped properly and allows execution of code. Update to Shopware 6.6.5.1 or 6.5.8.13 to receive a patch. For older versions of 6.2, 6.3, and 6.4, corresponding security measures are also available via a plugin.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
shopware/corePackagist
< 6.5.8.136.5.8.13
shopware/platformPackagist
< 6.5.8.136.5.8.13
shopware/platformPackagist
>= 6.6.0.0, < 6.6.5.16.6.5.1
shopware/corePackagist
>= 6.6.0.0, < 6.6.5.16.6.5.1

Affected products

1

Patches

4
8504ba7e56e5

NEXT-37397 - Security picks

https://github.com/shopware/shopwareSoner SayakciAug 7, 2024via ghsa
15 files changed · +158 12
  • .bc-exclude.php+2 0 modified
    @@ -42,6 +42,8 @@
             'Shopware\\\\Core\\\\Framework\\\\App\\\\Payment\\\\Payload\\\\Struct\\\\SyncPayPayload#__construct()',
             'Shopware\\\\Core\\\\Framework\\\\Api\\\\Sync\\\\FkReference#__construct\(\)',
     
    +        'Shopware\\\\Core\\\\Framework\\\\Context.*changed from callable.*',
    +
             // Removed boot method from Bundle
             'Shopware\\\\Core\\\\Framework\\\\Bundle#boot',
     
    
  • changelog/_unreleased/2024-07-24-context-object-improvements.md+8 0 added
    @@ -0,0 +1,8 @@
    +---
    +title: Context object improvements
    +issue: NEXT-37399
    +---
    +
    +# Core
    +
    +* Changed `\Shopware\Core\Framework\Context` to allow only \Closure in `enableInheritance`, `disableInheritance` and `scope` method to prevent misuse of the context object in sandbox environments.
    
  • changelog/_unreleased/2024-07-24-improve-aggregation-name-validation.md+8 0 added
    @@ -0,0 +1,8 @@
    +---
    +title: Improve aggregation name validation
    +issue: NEXT-37397
    +---
    +
    +# Core
    +
    +* Changed `\Shopware\Core\Framework\DataAbstractionLayer\Search\Parser\AggregationParser` to validate that the aggregation name does not contain question marks or colon,
    
  • changelog/_unreleased/2024-07-24-improve-feature-silent-token-validation.md+8 0 added
    @@ -0,0 +1,8 @@
    +---
    +title: Improve feature silent token validation
    +issue: NEXT-37398
    +---
    +
    +# Core
    +
    +* Changed `\Shopware\Core\Framework\Adapter\Twig\Node\FeatureCallSilentToken` to properly inject the feature flag into the compiled template file.
    
  • src/Core/Framework/Adapter/Twig/Node/FeatureCallSilentToken.php+3 1 modified
    @@ -24,7 +24,9 @@ public function compile(Compiler $compiler): void
         {
             $compiler
                 ->addDebugInfo($this)
    -            ->raw('\Shopware\Core\Framework\Feature::callSilentIfInactive(\'' . $this->flag . '\', function () use(&$context) { ')
    +            ->raw('\Shopware\Core\Framework\Feature::callSilentIfInactive(')
    +            ->string($this->flag)
    +            ->raw(', function () use(&$context) { ')
                 ->subcompile($this->getNode('body'))
                 ->raw('});');
         }
    
  • src/Core/Framework/Context.php+6 6 modified
    @@ -149,11 +149,11 @@ public function createWithVersionId(string $versionId): self
         /**
          * @template TReturn of mixed
          *
    -     * @param callable(Context): TReturn $callback
    +     * @param \Closure(Context): TReturn $callback
          *
          * @return TReturn the return value of the provided callback function
          */
    -    public function scope(string $scope, callable $callback)
    +    public function scope(string $scope, \Closure $callback)
         {
             $currentScope = $this->getScope();
             $this->scope = $scope;
    @@ -216,11 +216,11 @@ public function setRuleIds(array $ruleIds): void
         /**
          * @template TReturn of mixed
          *
    -     * @param callable(Context): TReturn $function
    +     * @param \Closure(Context): TReturn $function
          *
          * @return TReturn
          */
    -    public function enableInheritance(callable $function)
    +    public function enableInheritance(\Closure $function)
         {
             $previous = $this->considerInheritance;
             $this->considerInheritance = true;
    @@ -233,11 +233,11 @@ public function enableInheritance(callable $function)
         /**
          * @template TReturn of mixed
          *
    -     * @param callable(Context): TReturn $function
    +     * @param \Closure(Context): TReturn $function
          *
          * @return TReturn
          */
    -    public function disableInheritance(callable $function)
    +    public function disableInheritance(\Closure $function)
         {
             $previous = $this->considerInheritance;
             $this->considerInheritance = false;
    
  • src/Core/Framework/DataAbstractionLayer/DataAbstractionLayerException.php+11 0 modified
    @@ -44,6 +44,7 @@ class DataAbstractionLayerException extends HttpException
         public const INVALID_WRITE_INPUT = 'FRAMEWORK__INVALID_WRITE_INPUT';
         public const DECODE_HANDLED_BY_HYDRATOR = 'FRAMEWORK__DECODE_HANDLED_BY_HYDRATOR';
         public const ATTRIBUTE_NOT_FOUND = 'FRAMEWORK__ATTRIBUTE_NOT_FOUND';
    +    public const INVALID_AGGREGATION_NAME = 'FRAMEWORK__INVALID_AGGREGATION_NAME';
     
         public static function invalidSerializerField(string $expectedClass, Field $field): self
         {
    @@ -402,4 +403,14 @@ public static function canNotFindAttribute(string $attribute, string $property):
                 ['attribute' => $attribute, 'property' => $property]
             );
         }
    +
    +    public static function invalidAggregationName(string $name): self
    +    {
    +        return new self(
    +            Response::HTTP_BAD_REQUEST,
    +            self::INVALID_AGGREGATION_NAME,
    +            'Invalid aggregation name "{{ name }}", cannot contain question marks und colon.',
    +            ['name' => $name]
    +        );
    +    }
     }
    
  • src/Core/Framework/DataAbstractionLayer/Dbal/EntityAggregator.php+5 0 modified
    @@ -4,6 +4,7 @@
     
     use Doctrine\DBAL\Connection;
     use Shopware\Core\Framework\Context;
    +use Shopware\Core\Framework\DataAbstractionLayer\DataAbstractionLayerException;
     use Shopware\Core\Framework\DataAbstractionLayer\DefinitionInstanceRegistry;
     use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
     use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
    @@ -116,6 +117,10 @@ private function fetchAggregation(
             Criteria $criteria,
             Context $context
         ): AggregationResult {
    +        if (str_contains($aggregation->getName(), '?') || str_contains($aggregation->getName(), ':')) {
    +            throw DataAbstractionLayerException::invalidAggregationName($aggregation->getName());
    +        }
    +
             $clone = clone $criteria;
             $clone->resetAggregations();
             $clone->resetSorting();
    
  • src/Core/Framework/DataAbstractionLayer/Search/Parser/AggregationParser.php+6 0 modified
    @@ -199,6 +199,12 @@ private function parseAggregation(int $index, EntityDefinition $definition, arra
                 return null;
             }
     
    +        if (str_contains($name, '?') || str_contains($name, ':')) {
    +            $exceptions->add(new InvalidAggregationQueryException('The aggregation name should not contain a question mark or colon.'), '/aggregations/' . $index);
    +
    +            return null;
    +        }
    +
             $type = $aggregation['type'] ?? null;
     
             if (!\is_string($type) || empty($type) || is_numeric($type)) {
    
  • src/Core/Framework/Test/DataAbstractionLayer/Search/EntityAggregatorTest.php+13 0 modified
    @@ -11,6 +11,7 @@
     use Shopware\Core\Defaults;
     use Shopware\Core\DevOps\Environment\EnvironmentHelper;
     use Shopware\Core\Framework\Context;
    +use Shopware\Core\Framework\DataAbstractionLayer\DataAbstractionLayerException;
     use Shopware\Core\Framework\DataAbstractionLayer\Exception\InvalidAggregationQueryException;
     use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\DateHistogramAggregation;
     use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\FilterAggregation;
    @@ -1338,6 +1339,18 @@ public function testAggregationWithBacktickInName(): void
             $this->aggregator->aggregate($this->getContainer()->get(TaxDefinition::class), $criteria, $context);
         }
     
    +    public function testAggregationNameWithDisallowedName(): void
    +    {
    +        $context = Context::createDefaultContext();
    +
    +        $criteria = new Criteria();
    +        $criteria->addAggregation(new SumAggregation('foo?foo', 'taxRate'));
    +
    +        static::expectExceptionObject(DataAbstractionLayerException::invalidAggregationName('foo?foo'));
    +
    +        $this->aggregator->aggregate($this->getContainer()->get(TaxDefinition::class), $criteria, $context);
    +    }
    +
         private function insertData(): void
         {
             $repository = $this->getContainer()->get('product.repository');
    
  • src/Core/Framework/Test/DataAbstractionLayer/Search/Parser/AggregationParserTest.php+29 0 modified
    @@ -318,4 +318,33 @@ public function testICanCreateARangeAggregation(): void
             static::assertEquals($expectedRanges[0] + ['key' => '1-2'], $computedRanges[0]);
             static::assertEquals($expectedRanges[1] + ['key' => '2-3'], $computedRanges[1]);
         }
    +
    +    public function testQuestionMarkNotAllowedInAggregationName(): void
    +    {
    +        $criteria = new Criteria();
    +        $searchRequestException = new SearchRequestException();
    +        $this->parser->buildAggregations(
    +            self::getContainer()->get(ProductDefinition::class),
    +            [
    +                'aggregations' => [
    +                    [
    +                        'name' => 'max?agg',
    +                        'type' => 'max',
    +                        'field' => 'tax.taxRate',
    +                    ],
    +                ],
    +            ],
    +            $criteria,
    +            $searchRequestException
    +        );
    +
    +        $errors = iterator_to_array($searchRequestException->getErrors(), false);
    +        static::assertCount(1, $errors);
    +
    +        $error = array_shift($errors);
    +
    +        static::assertNotNull($error);
    +
    +        static::assertSame('The aggregation name should not contain a question mark or colon.', $error['detail']);
    +    }
     }
    
  • src/Core/System/SalesChannel/Entity/SalesChannelRepository.php+14 4 modified
    @@ -9,6 +9,7 @@
     use Shopware\Core\Framework\DataAbstractionLayer\Event\EntitySearchResultLoadedEvent;
     use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
     use Shopware\Core\Framework\DataAbstractionLayer\Field\AssociationField;
    +use Shopware\Core\Framework\DataAbstractionLayer\Field\ManyToManyAssociationField;
     use Shopware\Core\Framework\DataAbstractionLayer\Read\EntityReaderInterface;
     use Shopware\Core\Framework\DataAbstractionLayer\RepositorySearchDetector;
     use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\AggregationResultCollection;
    @@ -203,7 +204,7 @@ private function processCriteria(Criteria $topCriteria, SalesChannelContext $sal
             }
     
             $queue = [
    -            ['definition' => $this->definition, 'criteria' => $topCriteria],
    +            ['definition' => $this->definition, 'criteria' => $topCriteria, 'path' => ''],
             ];
     
             $maxCount = 100;
    @@ -216,8 +217,10 @@ private function processCriteria(Criteria $topCriteria, SalesChannelContext $sal
     
                 $definition = $cur['definition'];
                 $criteria = $cur['criteria'];
    +            $path = $cur['path'];
    +            $processedKey = $path . $definition::class;
     
    -            if (isset($processed[$definition::class])) {
    +            if (isset($processed[$processedKey])) {
                     continue;
                 }
     
    @@ -230,7 +233,7 @@ private function processCriteria(Criteria $topCriteria, SalesChannelContext $sal
                     $this->eventDispatcher->dispatch($event, $eventName);
                 }
     
    -            $processed[$definition::class] = true;
    +            $processed[$processedKey] = true;
     
                 foreach ($criteria->getAssociations() as $associationName => $associationCriteria) {
                     // find definition
    @@ -240,7 +243,14 @@ private function processCriteria(Criteria $topCriteria, SalesChannelContext $sal
                     }
     
                     $referenceDefinition = $field->getReferenceDefinition();
    -                $queue[] = ['definition' => $referenceDefinition, 'criteria' => $associationCriteria];
    +                $queue[] = ['definition' => $referenceDefinition, 'criteria' => $associationCriteria, 'path' => $path . '.' . $associationName];
    +
    +                if (!$field instanceof ManyToManyAssociationField) {
    +                    continue;
    +                }
    +
    +                $referenceDefinition = $field->getToManyReferenceDefinition();
    +                $queue[] = ['definition' => $referenceDefinition, 'criteria' => $associationCriteria, 'path' => $path . '.' . $associationName];
                 }
             }
         }
    
  • tests/unit/Core/Framework/Adapter/Twig/Node/FeatureCallSilentTokenTest.php+1 1 modified
    @@ -26,7 +26,7 @@ public function testCompile(): void
     
             $code = <<<'PHP'
     // line 1
    -\Shopware\Core\Framework\Feature::callSilentIfInactive('v6.5.0.0', function () use(&$context) { yield "test";
    +\Shopware\Core\Framework\Feature::callSilentIfInactive("v6.5.0.0", function () use(&$context) { yield "test";
     });
     PHP;
     
    
  • tests/unit/Core/Framework/Adapter/Twig/TokenParser/FeatureFlagCallTokenParserTest.php+5 0 modified
    @@ -59,6 +59,11 @@ public static function providerCode(): iterable
                 '{% do foo.call %}',
                 true,
             ];
    +
    +        yield 'test injection' => [
    +            '{% sw_silent_feature_call "aaa\' . system(\'id\') . \'bbb" %}{% do foo.call %}{% endsw_silent_feature_call %}',
    +            true,
    +        ];
         }
     }
     
    
  • tests/unit/Framework/ContextTest.php+39 0 added
    @@ -0,0 +1,39 @@
    +<?php declare(strict_types=1);
    +
    +namespace Shopware\Tests\Unit\Framework;
    +
    +use PHPUnit\Framework\Attributes\CoversClass;
    +use PHPUnit\Framework\Attributes\DataProvider;
    +use PHPUnit\Framework\TestCase;
    +use Shopware\Core\Framework\Context;
    +use Twig\Environment;
    +use Twig\Error\RuntimeError;
    +use Twig\Loader\ArrayLoader;
    +
    +/**
    + * @internal
    + */
    +#[CoversClass(Context::class)]
    +class ContextTest extends TestCase
    +{
    +    public static function twigMethodProviders(): \Generator
    +    {
    +        yield 'enableInheritance' => ['{{ context.enableInheritance("print_r") }}'];
    +        yield 'disableInheritance' => ['{{ context.disableInheritance("print_r") }}'];
    +        yield 'scope' => ['{{ context.scope("system", "print_r") }}'];
    +    }
    +
    +    #[DataProvider(methodName: 'twigMethodProviders')]
    +    public function testCallableCannotBeCalledFromTwig(string $tpl): void
    +    {
    +        $context = Context::createDefaultContext();
    +
    +        $twig = new Environment(new ArrayLoader([
    +            'tpl' => $tpl,
    +        ]));
    +
    +        static::expectException(RuntimeError::class);
    +
    +        $twig->render('tpl', ['context' => $context]);
    +    }
    +}
    
a784aa1cec06

NEXT-37397 - Security picks

https://github.com/shopware/coreSoner SayakciAug 7, 2024via ghsa
8 files changed · +87 11
  • Framework/Adapter/Twig/Node/FeatureCallSilentToken.php+3 1 modified
    @@ -24,7 +24,9 @@ public function compile(Compiler $compiler): void
         {
             $compiler
                 ->addDebugInfo($this)
    -            ->raw('\Shopware\Core\Framework\Feature::callSilentIfInactive(\'' . $this->flag . '\', function () use(&$context) { ')
    +            ->raw('\Shopware\Core\Framework\Feature::callSilentIfInactive(')
    +            ->string($this->flag)
    +            ->raw(', function () use(&$context) { ')
                 ->subcompile($this->getNode('body'))
                 ->raw('});');
         }
    
  • Framework/Context.php+6 6 modified
    @@ -149,11 +149,11 @@ public function createWithVersionId(string $versionId): self
         /**
          * @template TReturn of mixed
          *
    -     * @param callable(Context): TReturn $callback
    +     * @param \Closure(Context): TReturn $callback
          *
          * @return TReturn the return value of the provided callback function
          */
    -    public function scope(string $scope, callable $callback)
    +    public function scope(string $scope, \Closure $callback)
         {
             $currentScope = $this->getScope();
             $this->scope = $scope;
    @@ -216,11 +216,11 @@ public function setRuleIds(array $ruleIds): void
         /**
          * @template TReturn of mixed
          *
    -     * @param callable(Context): TReturn $function
    +     * @param \Closure(Context): TReturn $function
          *
          * @return TReturn
          */
    -    public function enableInheritance(callable $function)
    +    public function enableInheritance(\Closure $function)
         {
             $previous = $this->considerInheritance;
             $this->considerInheritance = true;
    @@ -233,11 +233,11 @@ public function enableInheritance(callable $function)
         /**
          * @template TReturn of mixed
          *
    -     * @param callable(Context): TReturn $function
    +     * @param \Closure(Context): TReturn $function
          *
          * @return TReturn
          */
    -    public function disableInheritance(callable $function)
    +    public function disableInheritance(\Closure $function)
         {
             $previous = $this->considerInheritance;
             $this->considerInheritance = false;
    
  • Framework/DataAbstractionLayer/DataAbstractionLayerException.php+11 0 modified
    @@ -44,6 +44,7 @@ class DataAbstractionLayerException extends HttpException
         public const INVALID_WRITE_INPUT = 'FRAMEWORK__INVALID_WRITE_INPUT';
         public const DECODE_HANDLED_BY_HYDRATOR = 'FRAMEWORK__DECODE_HANDLED_BY_HYDRATOR';
         public const ATTRIBUTE_NOT_FOUND = 'FRAMEWORK__ATTRIBUTE_NOT_FOUND';
    +    public const INVALID_AGGREGATION_NAME = 'FRAMEWORK__INVALID_AGGREGATION_NAME';
     
         public static function invalidSerializerField(string $expectedClass, Field $field): self
         {
    @@ -402,4 +403,14 @@ public static function canNotFindAttribute(string $attribute, string $property):
                 ['attribute' => $attribute, 'property' => $property]
             );
         }
    +
    +    public static function invalidAggregationName(string $name): self
    +    {
    +        return new self(
    +            Response::HTTP_BAD_REQUEST,
    +            self::INVALID_AGGREGATION_NAME,
    +            'Invalid aggregation name "{{ name }}", cannot contain question marks und colon.',
    +            ['name' => $name]
    +        );
    +    }
     }
    
  • Framework/DataAbstractionLayer/Dbal/EntityAggregator.php+5 0 modified
    @@ -4,6 +4,7 @@
     
     use Doctrine\DBAL\Connection;
     use Shopware\Core\Framework\Context;
    +use Shopware\Core\Framework\DataAbstractionLayer\DataAbstractionLayerException;
     use Shopware\Core\Framework\DataAbstractionLayer\DefinitionInstanceRegistry;
     use Shopware\Core\Framework\DataAbstractionLayer\EntityCollection;
     use Shopware\Core\Framework\DataAbstractionLayer\EntityDefinition;
    @@ -116,6 +117,10 @@ private function fetchAggregation(
             Criteria $criteria,
             Context $context
         ): AggregationResult {
    +        if (str_contains($aggregation->getName(), '?') || str_contains($aggregation->getName(), ':')) {
    +            throw DataAbstractionLayerException::invalidAggregationName($aggregation->getName());
    +        }
    +
             $clone = clone $criteria;
             $clone->resetAggregations();
             $clone->resetSorting();
    
  • Framework/DataAbstractionLayer/Search/Parser/AggregationParser.php+6 0 modified
    @@ -199,6 +199,12 @@ private function parseAggregation(int $index, EntityDefinition $definition, arra
                 return null;
             }
     
    +        if (str_contains($name, '?') || str_contains($name, ':')) {
    +            $exceptions->add(new InvalidAggregationQueryException('The aggregation name should not contain a question mark or colon.'), '/aggregations/' . $index);
    +
    +            return null;
    +        }
    +
             $type = $aggregation['type'] ?? null;
     
             if (!\is_string($type) || empty($type) || is_numeric($type)) {
    
  • Framework/Test/DataAbstractionLayer/Search/EntityAggregatorTest.php+13 0 modified
    @@ -11,6 +11,7 @@
     use Shopware\Core\Defaults;
     use Shopware\Core\DevOps\Environment\EnvironmentHelper;
     use Shopware\Core\Framework\Context;
    +use Shopware\Core\Framework\DataAbstractionLayer\DataAbstractionLayerException;
     use Shopware\Core\Framework\DataAbstractionLayer\Exception\InvalidAggregationQueryException;
     use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\DateHistogramAggregation;
     use Shopware\Core\Framework\DataAbstractionLayer\Search\Aggregation\Bucket\FilterAggregation;
    @@ -1338,6 +1339,18 @@ public function testAggregationWithBacktickInName(): void
             $this->aggregator->aggregate($this->getContainer()->get(TaxDefinition::class), $criteria, $context);
         }
     
    +    public function testAggregationNameWithDisallowedName(): void
    +    {
    +        $context = Context::createDefaultContext();
    +
    +        $criteria = new Criteria();
    +        $criteria->addAggregation(new SumAggregation('foo?foo', 'taxRate'));
    +
    +        static::expectExceptionObject(DataAbstractionLayerException::invalidAggregationName('foo?foo'));
    +
    +        $this->aggregator->aggregate($this->getContainer()->get(TaxDefinition::class), $criteria, $context);
    +    }
    +
         private function insertData(): void
         {
             $repository = $this->getContainer()->get('product.repository');
    
  • Framework/Test/DataAbstractionLayer/Search/Parser/AggregationParserTest.php+29 0 modified
    @@ -318,4 +318,33 @@ public function testICanCreateARangeAggregation(): void
             static::assertEquals($expectedRanges[0] + ['key' => '1-2'], $computedRanges[0]);
             static::assertEquals($expectedRanges[1] + ['key' => '2-3'], $computedRanges[1]);
         }
    +
    +    public function testQuestionMarkNotAllowedInAggregationName(): void
    +    {
    +        $criteria = new Criteria();
    +        $searchRequestException = new SearchRequestException();
    +        $this->parser->buildAggregations(
    +            self::getContainer()->get(ProductDefinition::class),
    +            [
    +                'aggregations' => [
    +                    [
    +                        'name' => 'max?agg',
    +                        'type' => 'max',
    +                        'field' => 'tax.taxRate',
    +                    ],
    +                ],
    +            ],
    +            $criteria,
    +            $searchRequestException
    +        );
    +
    +        $errors = iterator_to_array($searchRequestException->getErrors(), false);
    +        static::assertCount(1, $errors);
    +
    +        $error = array_shift($errors);
    +
    +        static::assertNotNull($error);
    +
    +        static::assertSame('The aggregation name should not contain a question mark or colon.', $error['detail']);
    +    }
     }
    
  • System/SalesChannel/Entity/SalesChannelRepository.php+14 4 modified
    @@ -9,6 +9,7 @@
     use Shopware\Core\Framework\DataAbstractionLayer\Event\EntitySearchResultLoadedEvent;
     use Shopware\Core\Framework\DataAbstractionLayer\Exception\InconsistentCriteriaIdsException;
     use Shopware\Core\Framework\DataAbstractionLayer\Field\AssociationField;
    +use Shopware\Core\Framework\DataAbstractionLayer\Field\ManyToManyAssociationField;
     use Shopware\Core\Framework\DataAbstractionLayer\Read\EntityReaderInterface;
     use Shopware\Core\Framework\DataAbstractionLayer\RepositorySearchDetector;
     use Shopware\Core\Framework\DataAbstractionLayer\Search\AggregationResult\AggregationResultCollection;
    @@ -203,7 +204,7 @@ private function processCriteria(Criteria $topCriteria, SalesChannelContext $sal
             }
     
             $queue = [
    -            ['definition' => $this->definition, 'criteria' => $topCriteria],
    +            ['definition' => $this->definition, 'criteria' => $topCriteria, 'path' => ''],
             ];
     
             $maxCount = 100;
    @@ -216,8 +217,10 @@ private function processCriteria(Criteria $topCriteria, SalesChannelContext $sal
     
                 $definition = $cur['definition'];
                 $criteria = $cur['criteria'];
    +            $path = $cur['path'];
    +            $processedKey = $path . $definition::class;
     
    -            if (isset($processed[$definition::class])) {
    +            if (isset($processed[$processedKey])) {
                     continue;
                 }
     
    @@ -230,7 +233,7 @@ private function processCriteria(Criteria $topCriteria, SalesChannelContext $sal
                     $this->eventDispatcher->dispatch($event, $eventName);
                 }
     
    -            $processed[$definition::class] = true;
    +            $processed[$processedKey] = true;
     
                 foreach ($criteria->getAssociations() as $associationName => $associationCriteria) {
                     // find definition
    @@ -240,7 +243,14 @@ private function processCriteria(Criteria $topCriteria, SalesChannelContext $sal
                     }
     
                     $referenceDefinition = $field->getReferenceDefinition();
    -                $queue[] = ['definition' => $referenceDefinition, 'criteria' => $associationCriteria];
    +                $queue[] = ['definition' => $referenceDefinition, 'criteria' => $associationCriteria, 'path' => $path . '.' . $associationName];
    +
    +                if (!$field instanceof ManyToManyAssociationField) {
    +                    continue;
    +                }
    +
    +                $referenceDefinition = $field->getToManyReferenceDefinition();
    +                $queue[] = ['definition' => $referenceDefinition, 'criteria' => $associationCriteria, 'path' => $path . '.' . $associationName];
                 }
             }
         }
    
445c6763cc09

NEXT-37398 - Improve validation of feature flag name in FeatureCallSilentToken

https://github.com/shopware/shopwareSoner SayakciJul 24, 2024via ghsa
2 files changed · +8 1
  • src/Core/Framework/Adapter/Twig/Node/FeatureCallSilentToken.php+3 1 modified
    @@ -22,7 +22,9 @@ public function compile(Compiler $compiler): void
         {
             $compiler
                 ->addDebugInfo($this)
    -            ->raw('\Shopware\Core\Framework\Feature::callSilentIfInactive(\'' . $this->flag . '\', function () use(&$context) { ')
    +            ->raw('\Shopware\Core\Framework\Feature::callSilentIfInactive(')
    +            ->string($this->flag)
    +            ->raw(', function () use(&$context) { ')
                 ->subcompile($this->getNode('body'))
                 ->raw('});');
         }
    
  • tests/unit/Core/Framework/Adapter/Twig/TokenParser/FeatureFlagCallTokenParserTest.php+5 0 modified
    @@ -60,6 +60,11 @@ public static function providerCode(): iterable
                 '{% do foo.call %}',
                 true,
             ];
    +
    +        yield 'test injection' => [
    +            '{% sw_silent_feature_call "aaa\' . system(\'id\') . \'bbb" %}{% do foo.call %}{% endsw_silent_feature_call %}',
    +            true,
    +        ];
         }
     }
     
    
d35ee2eda5c9

NEXT-37398 - Improve validation of feature flag name in FeatureCallSilentToken

https://github.com/shopware/coreSoner SayakciJul 24, 2024via ghsa
1 file changed · +3 1
  • Framework/Adapter/Twig/Node/FeatureCallSilentToken.php+3 1 modified
    @@ -22,7 +22,9 @@ public function compile(Compiler $compiler): void
         {
             $compiler
                 ->addDebugInfo($this)
    -            ->raw('\Shopware\Core\Framework\Feature::callSilentIfInactive(\'' . $this->flag . '\', function () use(&$context) { ')
    +            ->raw('\Shopware\Core\Framework\Feature::callSilentIfInactive(')
    +            ->string($this->flag)
    +            ->raw(', function () use(&$context) { ')
                 ->subcompile($this->getNode('body'))
                 ->raw('});');
         }
    

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

7

News mentions

0

No linked articles in our index yet.