CVE-2023-1879: 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.12.
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-04-05T17:15Z
Repository: https://github.com/thorsten/phpmyfaq
Language: PHP
Files changed: phpmyfaq/admin/category.edit.php, phpmyfaq/admin/category.main.php
Commit date: 2023-03-09 19:53:47 +0100
Commit message: fix: added missing conversion to HTML entities

Diff: diff --git a/phpmyfaq/admin/category.edit.php b/phpmyfaq/admin/category.edit.php
index a81f038817..b4d40ec7ef 100644
--- a/phpmyfaq/admin/category.edit.php
+++ b/phpmyfaq/admin/category.edit.php
@@ -17,10 +17,11 @@
 
 use phpMyFAQ\Category;
 use phpMyFAQ\Category\CategoryPermission;
 use phpMyFAQ\Filter;
 use phpMyFAQ\Helper\UserHelper;
+use phpMyFAQ\Strings;
 
 if (!defined('IS_VALID_PHPMYFAQ')) {
     http_response_code(400);
     exit();
 }
@@ -56,11 +57,12 @@ if ($user->perm->hasPermission($user->getUserId(), 'editcateg')) {
     } else {
         $allGroups = false;
         $restrictedGroups = true;
     }
 
-    $header = $PMF_LANG['ad_categ_edit_1'] . ' "' . $categoryData->getName() . '" ' . $PMF_LANG['ad_categ_edit_2'];
+    $header = $PMF_LANG['ad_categ_edit_1'] . ' "' . Strings::htmlentities($categoryData->getName()) .
+        '" ' . $PMF_LANG['ad_categ_edit_2'];
     ?>
         <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
           <h1 class="h2">
             <i aria-hidden="true" class="fa fa-folder"></i> <?= $header ?>
           </h1>
@@ -79,22 +81,22 @@ if ($user->perm->hasPermission($user->getUserId(), 'editcateg')) {
             <div class="form-group row">
               <label class="col-lg-2 col-form-label">
                   <?= $PMF_LANG['ad_categ_titel'] ?>:
               </label>
               <div class="col-lg-4">
-                <input type="text" id="name" name="name" value="<?= $categoryData->getName() ?>"
+                <input type="text" id="name" name="name" value="<?= Strings::htmlentities($categoryData->getName()) ?>"
                        class="form-control">
               </div>
             </div>
 
             <div class="form-group row">
               <label class="col-lg-2 col-form-label">
                   <?= $PMF_LANG['ad_categ_desc'] ?>:
               </label>
               <div class="col-lg-4">
                 <textarea id="description" name="description" rows="3"
-                          class="form-control"><?= $categoryData->getDescription() ?></textarea>
+                          class="form-control"><?= Strings::htmlentities($categoryData->getDescription()) ?></textarea>
               </div>
             </div>
 
             <div class="form-group row">
               <div class="offset-lg-2 col-lg-4">
diff --git a/phpmyfaq/admin/category.main.php b/phpmyfaq/admin/category.main.php
index 8e7c3cb706..77caf1fb82 100644
--- a/phpmyfaq/admin/category.main.php
+++ b/phpmyfaq/admin/category.main.php
@@ -153,12 +153,12 @@ if (!defined('IS_VALID_PHPMYFAQ')) {
                 $category->setUser($currentAdminUser);
                 $category->setGroups($currentAdminGroups);
 
                 $parentId = Filter::filterInput(INPUT_POST, 'parent_id', FILTER_VALIDATE_INT);
                 $categoryId = Filter::filterInput(INPUT_POST, 'id', FILTER_VALIDATE_INT);
-                $categoryLang = Filter::filterInput(INPUT_POST, 'catlang', FILTER_UNSAFE_RAW);
-                $existingImage = Filter::filterInput(INPUT_POST, 'existing_image', FILTER_UNSAFE_RAW);
+                $categoryLang = Filter::filterInput(INPUT_POST, 'catlang', FILTER_SANITIZE_SPECIAL_CHARS);
+                $existingImage = Filter::filterInput(INPUT_POST, 'existing_image', FILTER_SANITIZE_SPECIAL_CHARS);
                 $image = count($uploadedFile) ? $categoryImage->getFileName(
                     $categoryId,
                     $categoryLang
                 ) : $existingImage;
                 $categoryData = [

Vulnerable code:     $header = $PMF_LANG['ad_categ_edit_1'] . ' "' . $categoryData->getName() . '" ' . $PMF_LANG['ad_categ_edit_2'];
                <input type="text" id="name" name="name" value="<?= $categoryData->getName() ?>"
                          class="form-control"><?= $categoryData->getDescription() ?></textarea>
                $categoryLang = Filter::filterInput(INPUT_POST, 'catlang', FILTER_UNSAFE_RAW);
                $existingImage = Filter::filterInput(INPUT_POST, 'existing_image', FILTER_UNSAFE_RAW);
Fixed code: use phpMyFAQ\Strings;
    $header = $PMF_LANG['ad_categ_edit_1'] . ' "' . Strings::htmlentities($categoryData->getName()) .
        '" ' . $PMF_LANG['ad_categ_edit_2'];
                <input type="text" id="name" name="name" value="<?= Strings::htmlentities($categoryData->getName()) ?>"
                          class="form-control"><?= Strings::htmlentities($categoryData->getDescription()) ?></textarea>
                $categoryLang = Filter::filterInput(INPUT_POST, 'catlang', FILTER_SANITIZE_SPECIAL_CHARS);
                $existingImage = Filter::filterInput(INPUT_POST, 'existing_image', FILTER_SANITIZE_SPECIAL_CHARS);