CVE-2023-2999: 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.1.14.
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: 6.1
Published: 2023-05-31T01:15Z
Repository: https://github.com/thorsten/phpmyfaq
Language: PHP
Files changed: composer.json, composer.lock, phpmyfaq/faq.php, phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php
Commit date: 2023-05-03 16:53:01 +0200
Commit message: fix: added HtmlSanitizer

Diff: diff --git a/composer.json b/composer.json
index d2821f40d8c..96ddceab90e 100644
--- a/composer.json
+++ b/composer.json
@@ -30,11 +30,12 @@
     "ext-filter": "*",
     "ext-gd": "*",
     "ext-json": "*",
     "ext-xml": "*",
     "ext-zip": "*",
-    "ext-xmlwriter": "*"
+    "ext-xmlwriter": "*",
+    "tgalopin/html-sanitizer": "^1.5"
   },
   "require-dev": {
     "phpunit/phpunit": "9.*",
     "doctrine/instantiator": "1.*",
     "symfony/yaml": "5.*",
diff --git a/composer.lock b/composer.lock
index 5a94daca611..e5b76a19d6f 100644
--- a/composer.lock
+++ b/composer.lock
@@ -2,11 +2,11 @@
     "_readme": [
         "This file locks the dependencies of your project to a known state",
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "0411bf4e5e79e9aceafffbde9cbbe148",
+    "content-hash": "9b3bd5e2f7bec855a914710dc2959459",
     "packages": [
         {
             "name": "abraham/twitteroauth",
             "version": "4.0.1",
             "source": {
@@ -608,10 +608,147 @@
             "support": {
                 "source": "https://github.com/ezimuel/ringphp/tree/1.2.2"
             },
             "time": "2022-12-07T11:28:53+00:00"
         },
+        {
+            "name": "league/uri-parser",
+            "version": "1.4.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/thephpleague/uri-parser.git",
+                "reference": "671548427e4c932352d9b9279fdfa345bf63fa00"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/thephpleague/uri-parser/zipball/671548427e4c932352d9b9279fdfa345bf63fa00",
+                "reference": "671548427e4c932352d9b9279fdfa345bf63fa00",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=7.0.0"
+            },
+            "require-dev": {
+                "friendsofphp/php-cs-fixer": "^2.0",
+                "phpstan/phpstan": "^0.9.2",
+                "phpstan/phpstan-phpunit": "^0.9.4",
+                "phpstan/phpstan-strict-rules": "^0.9.0",
+                "phpunit/phpunit": "^6.0"
+            },
+            "suggest": {
+                "ext-intl": "Allow parsing RFC3987 compliant hosts",
+                "league/uri-schemes": "Allow validating and normalizing URI parsing results"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.x-dev"
+                }
+            },
+            "autoload": {
+                "files": [
+                    "src/functions_include.php"
+                ],
+                "psr-4": {
+                    "League\\Uri\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Ignace Nyamagana Butera",
+                    "email": "nyamsprod@gmail.com",
+                    "homepage": "https://nyamsprod.com"
+                }
+            ],
+            "description": "userland URI parser RFC 3986 compliant",
+            "homepage": "https://github.com/thephpleague/uri-parser",
+            "keywords": [
+                "parse_url",
+                "parser",
+                "rfc3986",
+                "rfc3987",
+                "uri",
+                "url"
+            ],
+            "support": {
+                "issues": "https://github.com/thephpleague/uri-parser/issues",
+                "source": "https://github.com/thephpleague/uri-parser/tree/master"
+            },
+            "abandoned": true,
+            "time": "2018-11-22T07:55:51+00:00"
+        },
+        {
+            "name": "masterminds/html5",
+            "version": "2.8.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/Masterminds/html5-php.git",
+                "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3",
+                "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "php": ">=5.3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8"
+            },
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "2.7-dev"
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "Masterminds\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Matt Butcher",
+                    "email": "technosophos@gmail.com"
+                },
+                {
+                    "name": "Matt Farina",
+                    "email": "matt@mattfarina.com"
+                },
+                {
+                    "name": "Asmir Mustafic",
+                    "email": "goetas@gmail.com"
+                }
+            ],
+            "description": "An HTML5 parser and serializer.",
+            "homepage": "http://masterminds.github.io/html5-php",
+            "keywords": [
+                "HTML5",
+                "dom",
+                "html",
+                "parser",
+                "querypath",
+                "serializer",
+                "xml"
+            ],
+            "support": {
+                "issues": "https://github.com/Masterminds/html5-php/issues",
+                "source": "https://github.com/Masterminds/html5-php/tree/2.8.0"
+            },
+            "time": "2023-04-26T07:27:39+00:00"
+        },
         {
             "name": "monolog/monolog",
             "version": "2.9.1",
             "source": {
                 "type": "git",
@@ -1682,10 +1819,59 @@
                     "url": "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&currency_code=GBP&business=paypal@tecnick.com&item_name=donation%20for%20tcpdf%20project",
                     "type": "custom"
                 }
             ],
             "time": "2022-12-17T10:28:59+00:00"
+        },
+        {
+            "name": "tgalopin/html-sanitizer",
+            "version": "1.5.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/tgalopin/html-sanitizer.git",
+                "reference": "5d02dcb6f2ea4f505731eac440798caa1b3b0913"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/tgalopin/html-sanitizer/zipball/5d02dcb6f2ea4f505731eac440798caa1b3b0913",
+                "reference": "5d02dcb6f2ea4f505731eac440798caa1b3b0913",
+                "shasum": ""
+            },
+            "require": {
+                "ext-dom": "*",
+                "league/uri-parser": "^1.4.1",
+                "masterminds/html5": "^2.4",
+                "php": ">=7.1",
+                "psr/log": "^1.0|^2.0|^3.0"
+            },
+            "require-dev": {
+                "phpunit/phpunit": "^7.4",
+                "symfony/var-dumper": "^4.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-4": {
+                    "HtmlSanitizer\\": "src"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Titouan Galopin",
+                    "email": "galopintitouan@gmail.com"
+                }
+            ],
+            "description": "Sanitize untrustworthy HTML user input",
+            "support": {
+                "issues": "https://github.com/tgalopin/html-sanitizer/issues",
+                "source": "https://github.com/tgalopin/html-sanitizer/tree/1.5.0"
+            },
+            "abandoned": "symfony/html-sanitizer",
+            "time": "2021-09-14T08:27:50+00:00"
         }
     ],
     "packages-dev": [
         {
             "name": "doctrine/instantiator",
diff --git a/phpmyfaq/faq.php b/phpmyfaq/faq.php
index 6895aa0987e..dab7d6fe2d5 100644
--- a/phpmyfaq/faq.php
+++ b/phpmyfaq/faq.php
@@ -338,11 +338,11 @@ $template->parse(
     [
         'baseHref' => $faqSystem->getSystemUri($faqConfig),
         'solutionId' => $faq->faqRecord['solution_id'],
         'solutionIdLink' => Link::getSystemRelativeUri() . '?solution_id=' . $faq->faqRecord['solution_id'],
         'question' => $question,
-        'answer' => $answer,
+        'answer' => $faqHelper->cleanUpContent($answer),
         'faqDate' => $date->format($faq->faqRecord['date']),
         'faqAuthor' => Strings::htmlentities($author),
         'editThisEntry' => $editThisEntry,
         'msgPdf' => $PMF_LANG['msgPDF'],
         'msgPrintFaq' => $PMF_LANG['msgPrintArticle'],
diff --git a/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php b/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php
index 3c6cd8a9c7d..6cb03b15c3f 100644
--- a/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php
+++ b/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php
@@ -16,10 +16,11 @@
  */
 
 namespace phpMyFAQ\Helper;
 
 use Exception;
+use HtmlSanitizer\Sanitizer;
 use ParsedownExtra;
 use phpMyFAQ\Category;
 use phpMyFAQ\Configuration;
 use phpMyFAQ\Date;
 use phpMyFAQ\Faq;
@@ -234,6 +235,20 @@ class FaqHelper extends Helper
             }
         }
 
         return $output;
     }
+
+
+    /**
+     * Remove <script> tags, we don't need them
+     *
+     * @param string $content
+     * @return string
+     */
+    public function cleanUpContent(string $content): string
+    {
+        $htmlSanitizer = Sanitizer::create(['extensions' => ['basic']]);
+
+        return $htmlSanitizer->sanitize($content);
+    }
 }

Vulnerable code:     "ext-xmlwriter": "*"
    "content-hash": "0411bf4e5e79e9aceafffbde9cbbe148",
        'answer' => $answer,
Fixed code:     "ext-xmlwriter": "*",
    "tgalopin/html-sanitizer": "^1.5"
    "content-hash": "9b3bd5e2f7bec855a914710dc2959459",
        {
            "name": "league/uri-parser",
            "version": "1.4.1",
            "source": {
                "type": "git",
                "url": "https://github.com/thephpleague/uri-parser.git",
                "reference": "671548427e4c932352d9b9279fdfa345bf63fa00"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/thephpleague/uri-parser/zipball/671548427e4c932352d9b9279fdfa345bf63fa00",
                "reference": "671548427e4c932352d9b9279fdfa345bf63fa00",
                "shasum": ""
            },
            "require": {
                "php": ">=7.0.0"
            },
            "require-dev": {
                "friendsofphp/php-cs-fixer": "^2.0",
                "phpstan/phpstan": "^0.9.2",
                "phpstan/phpstan-phpunit": "^0.9.4",
                "phpstan/phpstan-strict-rules": "^0.9.0",
                "phpunit/phpunit": "^6.0"
            },
            "suggest": {
                "ext-intl": "Allow parsing RFC3987 compliant hosts",
                "league/uri-schemes": "Allow validating and normalizing URI parsing results"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "1.x-dev"
                }
            },
            "autoload": {
                "files": [
                    "src/functions_include.php"
                ],
                "psr-4": {
                    "League\\Uri\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Ignace Nyamagana Butera",
                    "email": "nyamsprod@gmail.com",
                    "homepage": "https://nyamsprod.com"
                }
            ],
            "description": "userland URI parser RFC 3986 compliant",
            "homepage": "https://github.com/thephpleague/uri-parser",
            "keywords": [
                "parse_url",
                "parser",
                "rfc3986",
                "rfc3987",
                "uri",
                "url"
            ],
            "support": {
                "issues": "https://github.com/thephpleague/uri-parser/issues",
                "source": "https://github.com/thephpleague/uri-parser/tree/master"
            },
            "abandoned": true,
            "time": "2018-11-22T07:55:51+00:00"
        },
        {
            "name": "masterminds/html5",
            "version": "2.8.0",
            "source": {
                "type": "git",
                "url": "https://github.com/Masterminds/html5-php.git",
                "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/Masterminds/html5-php/zipball/3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3",
                "reference": "3c5d5a56d56f48a1ca08a0670f0f80c1dad368f3",
                "shasum": ""
            },
            "require": {
                "ext-dom": "*",
                "php": ">=5.3.0"
            },
            "require-dev": {
                "phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6 || ^7 || ^8"
            },
            "type": "library",
            "extra": {
                "branch-alias": {
                    "dev-master": "2.7-dev"
                }
            },
            "autoload": {
                "psr-4": {
                    "Masterminds\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Matt Butcher",
                    "email": "technosophos@gmail.com"
                },
                {
                    "name": "Matt Farina",
                    "email": "matt@mattfarina.com"
                },
                {
                    "name": "Asmir Mustafic",
                    "email": "goetas@gmail.com"
                }
            ],
            "description": "An HTML5 parser and serializer.",
            "homepage": "http://masterminds.github.io/html5-php",
            "keywords": [
                "HTML5",
                "dom",
                "html",
                "parser",
                "querypath",
                "serializer",
                "xml"
            ],
            "support": {
                "issues": "https://github.com/Masterminds/html5-php/issues",
                "source": "https://github.com/Masterminds/html5-php/tree/2.8.0"
            },
            "time": "2023-04-26T07:27:39+00:00"
        },
        },
        {
            "name": "tgalopin/html-sanitizer",
            "version": "1.5.0",
            "source": {
                "type": "git",
                "url": "https://github.com/tgalopin/html-sanitizer.git",
                "reference": "5d02dcb6f2ea4f505731eac440798caa1b3b0913"
            },
            "dist": {
                "type": "zip",
                "url": "https://api.github.com/repos/tgalopin/html-sanitizer/zipball/5d02dcb6f2ea4f505731eac440798caa1b3b0913",
                "reference": "5d02dcb6f2ea4f505731eac440798caa1b3b0913",
                "shasum": ""
            },
            "require": {
                "ext-dom": "*",
                "league/uri-parser": "^1.4.1",
                "masterminds/html5": "^2.4",
                "php": ">=7.1",
                "psr/log": "^1.0|^2.0|^3.0"
            },
            "require-dev": {
                "phpunit/phpunit": "^7.4",
                "symfony/var-dumper": "^4.1"
            },
            "type": "library",
            "autoload": {
                "psr-4": {
                    "HtmlSanitizer\\": "src"
                }
            },
            "notification-url": "https://packagist.org/downloads/",
            "license": [
                "MIT"
            ],
            "authors": [
                {
                    "name": "Titouan Galopin",
                    "email": "galopintitouan@gmail.com"
                }
            ],
            "description": "Sanitize untrustworthy HTML user input",
            "support": {
                "issues": "https://github.com/tgalopin/html-sanitizer/issues",
                "source": "https://github.com/tgalopin/html-sanitizer/tree/1.5.0"
            },
            "abandoned": "symfony/html-sanitizer",
            "time": "2021-09-14T08:27:50+00:00"
        'answer' => $faqHelper->cleanUpContent($answer),
use HtmlSanitizer\Sanitizer;


    /**
     * Remove <script> tags, we don't need them
     *
     * @param string $content
     * @return string
     */
    public function cleanUpContent(string $content): string
    {
        $htmlSanitizer = Sanitizer::create(['extensions' => ['basic']]);

        return $htmlSanitizer->sanitize($content);
    }