Vulnerability: Cross-site Scripting in pimcore pimcore is vulnerable to Stored XSS at Name field in the setting tab of the Global Targeting Rules.
Vulnerability ID: GHSA-455w-gv5p-wgg3
CWE: CWE-79
Severity score: 5.4
Project: https://github.com/pimcore/pimcore
Published: 2022-01-26
File: bundles/AdminBundle/Controller/Admin/TargetingController.php
Commit message: [Targeting] Escape/validate names of rules properly (#11205)

* [Targeting] Escape/validate names of rules properly

* Update bundles/AdminBundle/Controller/Admin/TargetingController.php

Co-authored-by: Jacob Dreesen <j.dreesen@neusta.de>

Co-authored-by: Jacob Dreesen <j.dreesen@neusta.de>
Commit author: Bernhard Rusch

Vulnerable version (before fix):
 class TargetingController extends AdminController implements KernelControllerEve {     // RULES      /**      * @Route("/rule/list", name="pimcore_admin_targeting_rulelist", methods={"GET"})      * public function ruleListAction(Request $request)         foreach ($list->load() as $target) {             $targets[] = [                 'id' => $target->getId(),                 'text' => $target->getName(),                 'active' => $target->getActive(),                 'qtip' => 'ID: ' . $target->getId(),             ]; public function ruleListAction(Request $request)     public function ruleAddAction(Request $request)     {         $target = new Targeting\Rule();         $target->setName($request->get('name'));         $target->save();          return $this->adminJson(['success' => true, 'id' => $target->getId()]); public function ruleSaveAction(Request $request)         /** @var Targeting\Rule|Targeting\Rule\Dao $target */         $target = Targeting\Rule::getById($request->get('id'));         $target->setValues($data['settings']);         $target->setConditions($data['conditions']);         $target->setActions($data['actions']);         $target->save(); public function targetGroupListAction(Request $request)         foreach ($list->load() as $targetGroup) {             $targetGroups[] = [                 'id' => $targetGroup->getId(),                 'text' => $targetGroup->getName(),                 'active' => $targetGroup->getActive(),                 'qtip' => $targetGroup->getId(),             ]; public function targetGroupAddAction(Request $request, CoreCacheHandler $cache,     {         /** @var TargetGroup|TargetGroup\Dao $targetGroup */         $targetGroup = new TargetGroup();         $targetGroup->setName($request->get('name'));         $targetGroup->save();          $event = new TargetGroupEvent($targetGroup); public function targetGroupSaveAction(Request $request, CoreCacheHandler $cache,         /** @var TargetGroup|TargetGroup\Dao $targetGroup */         $targetGroup = TargetGroup::getById($request->get('id'));         $targetGroup->setValues($data['settings']);         $targetGroup->save();          $event = new TargetGroupEvent($targetGroup);

Fixed version (after fix):
 class TargetingController extends AdminController implements KernelControllerEve {     // RULES      private function correctName(string $name): string     {         return preg_replace('/[#?*:\\\\<>|"%&@=;+]/', '-', $name);     }      /**      * @Route("/rule/list", name="pimcore_admin_targeting_rulelist", methods={"GET"})      * public function ruleListAction(Request $request)         foreach ($list->load() as $target) {             $targets[] = [                 'id' => $target->getId(),                 'text' => htmlspecialchars($target->getName()),                 'active' => $target->getActive(),                 'qtip' => 'ID: ' . $target->getId(),             ]; public function ruleListAction(Request $request)     public function ruleAddAction(Request $request)     {         $target = new Targeting\Rule();         $target->setName($this->correctName($request->get('name')));         $target->save();          return $this->adminJson(['success' => true, 'id' => $target->getId()]); public function ruleSaveAction(Request $request)         /** @var Targeting\Rule|Targeting\Rule\Dao $target */         $target = Targeting\Rule::getById($request->get('id'));         $target->setValues($data['settings']);         $target->setName($this->correctName($target->getName()));         $target->setConditions($data['conditions']);         $target->setActions($data['actions']);         $target->save(); public function targetGroupListAction(Request $request)         foreach ($list->load() as $targetGroup) {             $targetGroups[] = [                 'id' => $targetGroup->getId(),                 'text' => htmlspecialchars($targetGroup->getName()),                 'active' => $targetGroup->getActive(),                 'qtip' => $targetGroup->getId(),             ]; public function targetGroupAddAction(Request $request, CoreCacheHandler $cache,     {         /** @var TargetGroup|TargetGroup\Dao $targetGroup */         $targetGroup = new TargetGroup();         $targetGroup->setName($this->correctName($request->get('name')));         $targetGroup->save();          $event = new TargetGroupEvent($targetGroup); public function targetGroupSaveAction(Request $request, CoreCacheHandler $cache,         /** @var TargetGroup|TargetGroup\Dao $targetGroup */         $targetGroup = TargetGroup::getById($request->get('id'));         $targetGroup->setValues($data['settings']);         $targetGroup->setName($this->correctName($targetGroup->getName()));         $targetGroup->save();          $event = new TargetGroupEvent($targetGroup);

Patch:
patch: @@ -37,6 +37,11 @@ class TargetingController extends AdminController implements KernelControllerEve
 {
     // RULES
 
+    private function correctName(string $name): string
+    {
+        return preg_replace('/[#?*:\\\\<>|"%&@=;+]/', '-', $name);
+    }
+
     /**
      * @Route("/rule/list", name="pimcore_admin_targeting_rulelist", methods={"GET"})
      *
@@ -55,7 +60,7 @@ public function ruleListAction(Request $request)
         foreach ($list->load() as $target) {
             $targets[] = [
                 'id' => $target->getId(),
-                'text' => $target->getName(),
+                'text' => htmlspecialchars($target->getName()),
                 'active' => $target->getActive(),
                 'qtip' => 'ID: ' . $target->getId(),
             ];
@@ -74,7 +79,7 @@ public function ruleListAction(Request $request)
     public function ruleAddAction(Request $request)
     {
         $target = new Targeting\Rule();
-        $target->setName($request->get('name'));
+        $target->setName($this->correctName($request->get('name')));
         $target->save();
 
         return $this->adminJson(['success' => true, 'id' => $target->getId()]);
@@ -129,6 +134,7 @@ public function ruleSaveAction(Request $request)
         /** @var Targeting\Rule|Targeting\Rule\Dao $target */
         $target = Targeting\Rule::getById($request->get('id'));
         $target->setValues($data['settings']);
+        $target->setName($this->correctName($target->getName()));
         $target->setConditions($data['conditions']);
         $target->setActions($data['actions']);
         $target->save();
@@ -208,7 +214,7 @@ public function targetGroupListAction(Request $request)
         foreach ($list->load() as $targetGroup) {
             $targetGroups[] = [
                 'id' => $targetGroup->getId(),
-                'text' => $targetGroup->getName(),
+                'text' => htmlspecialchars($targetGroup->getName()),
                 'active' => $targetGroup->getActive(),
                 'qtip' => $targetGroup->getId(),
             ];
@@ -230,7 +236,7 @@ public function targetGroupAddAction(Request $request, CoreCacheHandler $cache,
     {
         /** @var TargetGroup|TargetGroup\Dao $targetGroup */
         $targetGroup = new TargetGroup();
-        $targetGroup->setName($request->get('name'));
+        $targetGroup->setName($this->correctName($request->get('name')));
         $targetGroup->save();
 
         $event = new TargetGroupEvent($targetGroup);
@@ -300,6 +306,7 @@ public function targetGroupSaveAction(Request $request, CoreCacheHandler $cache,
         /** @var TargetGroup|TargetGroup\Dao $targetGroup */
         $targetGroup = TargetGroup::getById($request->get('id'));
         $targetGroup->setValues($data['settings']);
+        $targetGroup->setName($this->correctName($targetGroup->getName()));
         $targetGroup->save();
 
         $event = new TargetGroupEvent($targetGroup);
path: bundles/AdminBundle/Controller/Admin/TargetingController.php