CVE-2023-2753: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Cross-site Scripting (XSS) - Stored in GitHub repository thorsten/phpmyfaq prior to 3.2.0-beta.
CWE description: 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.
CVSS v3 base score: 5.4
Published: 2023-05-17T08:15Z
Repository: https://github.com/thorsten/phpmyfaq
Language: PHP
Files changed: phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php, tests/phpMyFAQ/Helper/FaqHelperTest.php
Commit date: 2023-04-13 07:40:37 +0200
Commit message: fix: remove HTML event attributes

Diff: diff --git a/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php b/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php
index c482b1a7126..8d9a8c581b2 100644
--- a/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php
+++ b/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php
@@ -16,10 +16,11 @@
  */
 
 namespace phpMyFAQ\Helper;
 
 use DOMDocument;
+use DOMXPath;
 use Exception;
 use ParsedownExtra;
 use phpMyFAQ\Category;
 use phpMyFAQ\Configuration;
 use phpMyFAQ\Date;
@@ -243,8 +244,16 @@ class FaqHelper extends Helper
 
         for ($i = 0; $i < $scriptTags->length; $i++) {
             $scriptTags->item($i)->parentNode->removeChild($scriptTags->item($i));
         }
 
-        return preg_replace(['/\r/', '/\n/'], '', $document->saveHTML());
+        $xpath = new DOMXPath($document);
+        $onAttributes = $xpath->query("//*/@*[starts-with(name(), 'on')]");
+        foreach ($onAttributes as $onAttribute) {
+            $onAttribute->ownerElement->removeAttributeNode($onAttribute);
+        }
+
+        $body = $xpath->query('body')->item(0);
+
+        return preg_replace(['/\r/', '/\n/'], '', $document->saveHTML($body));
     }
 }
diff --git a/tests/phpMyFAQ/Helper/FaqHelperTest.php b/tests/phpMyFAQ/Helper/FaqHelperTest.php
index ead622c621d..1de4335720a 100644
--- a/tests/phpMyFAQ/Helper/FaqHelperTest.php
+++ b/tests/phpMyFAQ/Helper/FaqHelperTest.php
@@ -60,12 +60,12 @@ class FaqHelperTest extends TestCase
         );
     }
 
     public function testCleanUpContent(): void
     {
-        $content = '<p>Some text <script>alert("Hello, world!");</script></p>';
-        $expectedOutput = '<p>Some text </p>';
+        $content = '<p>Some text <script>alert("Hello, world!");</script><img src=foo onerror=alert(document.cookie)></p>';
+        $expectedOutput = '<p>Some text <img src="foo"></p>';
 
         $actualOutput = $this->faqHelper->cleanUpContent($content);
 
         $this->assertEquals($expectedOutput, $actualOutput);
     }

Vulnerable code:         return preg_replace(['/\r/', '/\n/'], '', $document->saveHTML());
        $content = '<p>Some text <script>alert("Hello, world!");</script></p>';
        $expectedOutput = '<p>Some text </p>';
Fixed code: use DOMXPath;
        $xpath = new DOMXPath($document);
        $onAttributes = $xpath->query("//*/@*[starts-with(name(), 'on')]");
        foreach ($onAttributes as $onAttribute) {
            $onAttribute->ownerElement->removeAttributeNode($onAttribute);
        }

        $body = $xpath->query('body')->item(0);

        return preg_replace(['/\r/', '/\n/'], '', $document->saveHTML($body));
        $content = '<p>Some text <script>alert("Hello, world!");</script><img src=foo onerror=alert(document.cookie)></p>';
        $expectedOutput = '<p>Some text <img src="foo"></p>';