CVE-2023-0313: 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.10.
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-01-15T22:15Z
Repository: https://github.com/thorsten/phpmyfaq
Language: PHP
Files changed: phpmyfaq/admin/category.main.php, phpmyfaq/admin/news.php, phpmyfaq/faq.php, phpmyfaq/index.php, phpmyfaq/news.php, phpmyfaq/src/Bootstrap.php, phpmyfaq/src/phpMyFAQ/Category.php, phpmyfaq/src/phpMyFAQ/Database/DatabaseHelper.php, phpmyfaq/src/phpMyFAQ/Helper/CategoryHelper.php, phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php, phpmyfaq/src/phpMyFAQ/Helper/QuestionHelper.php, phpmyfaq/src/phpMyFAQ/Helper/TagsHelper.php, phpmyfaq/src/phpMyFAQ/News.php, phpmyfaq/src/phpMyFAQ/Utils.php, phpmyfaq/startpage.php
Commit date: 2022-12-15 21:11:57 +0100
Commit message: fix: added missing conversion to HTML entities

Diff: diff --git a/phpmyfaq/admin/category.main.php b/phpmyfaq/admin/category.main.php
index 34e8d0d1d7..d55552c716 100644
--- a/phpmyfaq/admin/category.main.php
+++ b/phpmyfaq/admin/category.main.php
@@ -77,12 +77,12 @@ if (!defined('IS_VALID_PHPMYFAQ')) {
                 $parentId = Filter::filterInput(INPUT_POST, 'parent_id', FILTER_VALIDATE_INT);
                 $categoryId = $faqConfig->getDb()->nextId(Database::getTablePrefix() . 'faqcategories', 'id');
                 $categoryLang = Filter::filterInput(INPUT_POST, 'lang', FILTER_UNSAFE_RAW);
                 $categoryData = [
                     'lang' => $categoryLang,
-                    'name' => Filter::filterInput(INPUT_POST, 'name', FILTER_UNSAFE_RAW),
-                    'description' => Filter::filterInput(INPUT_POST, 'description', FILTER_UNSAFE_RAW),
+                    'name' => Filter::filterInput(INPUT_POST, 'name', FILTER_SANITIZE_SPECIAL_CHARS),
+                    'description' => Filter::filterInput(INPUT_POST, 'description', FILTER_SANITIZE_SPECIAL_CHARS),
                     'user_id' => Filter::filterInput(INPUT_POST, 'user_id', FILTER_VALIDATE_INT),
                     'group_id' => Filter::filterInput(INPUT_POST, 'group_id', FILTER_VALIDATE_INT),
                     'active' => Filter::filterInput(INPUT_POST, 'active', FILTER_VALIDATE_INT),
                     'image' => $categoryImage->getFileName($categoryId, $categoryLang),
                     'show_home' => Filter::filterInput(INPUT_POST, 'show_home', FILTER_VALIDATE_INT)
diff --git a/phpmyfaq/admin/news.php b/phpmyfaq/admin/news.php
index a055c4fe5d..b2a97d5dc6 100644
--- a/phpmyfaq/admin/news.php
+++ b/phpmyfaq/admin/news.php
@@ -5,25 +5,25 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public License,
  * v. 2.0. If a copy of the MPL was not distributed with this file, You can
  * obtain one at http://mozilla.org/MPL/2.0/.
  *
- * @package phpMyFAQ
- * @author Thorsten Rinne <thorsten@phpmyfaq.de>
- * @author Matteo Scaramuccia <matteo@phpmyfaq.de>
+ * @package   phpMyFAQ
+ * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
+ * @author    Matteo Scaramuccia <matteo@phpmyfaq.de>
  * @copyright 2003-2022 phpMyFAQ Team
- * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
- * @link https://www.phpmyfaq.de
- * @since 2003-02-23
+ * @license   http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
+ * @link      https://www.phpmyfaq.de
+ * @since     2003-02-23
  */
 
 use phpMyFAQ\Comments;
 use phpMyFAQ\Date;
 use phpMyFAQ\Entity\CommentType;
 use phpMyFAQ\Filter;
 use phpMyFAQ\Helper\LanguageHelper;
-use phpMyFAQ\News;
+use phpMyFAQ\News;use phpMyFAQ\Strings;
 
 if (!defined('IS_VALID_PHPMYFAQ')) {
     http_response_code(400);
     exit();
 }
@@ -64,19 +64,23 @@ if ('add-news' == $action && $user->perm->hasPermission($user->getUserId(), 'add
                             <textarea name="news" rows="5" class="form-control" id="news"></textarea>
                         </div>
                     </div>
 
                     <div class="form-group row">
-                        <label class="col-3 col-form-label" for="authorName"><?= $PMF_LANG['ad_news_author_name'] ?></label>
+                        <label class="col-3 col-form-label" for="authorName">
+                        <?= $PMF_LANG['ad_news_author_name'] ?>
+                        </label>
                         <div class="col-9">
                             <input class="form-control" type="text" name="authorName" id="authorName"
                                    value="<?= $user->getUserData('display_name') ?>">
                         </div>
                     </div>
 
                     <div class="form-group row">
-                        <label class="col-3 col-form-label" for="authorEmail"><?= $PMF_LANG['ad_news_author_email'] ?></label>
+                        <label class="col-3 col-form-label" for="authorEmail">
+                        <?= $PMF_LANG['ad_news_author_email'] ?>
+                        </label>
                         <div class="col-9">
                             <input class="form-control" type="email" name="authorEmail" id="authorEmail"
                                    value="<?= $user->getUserData('email') ?>">
                         </div>
                     </div>
@@ -92,11 +96,13 @@ if ('add-news' == $action && $user->perm->hasPermission($user->getUserId(), 'add
                             </label>
                         </div>
                     </div>
 
                     <div class="form-group row">
-                        <label class="col-3 col-form-label" for="comment"><?= $PMF_LANG['ad_news_allowComments'] ?></label>
+                        <label class="col-3 col-form-label" for="comment">
+                        <?= $PMF_LANG['ad_news_allowComments'] ?>
+                        </label>
                         <div class="col-9 checkbox">
                             <label>
                                 <input type="checkbox" name="comment" id="comment" value="y">
                                 <?= $PMF_LANG['ad_gen_yes'] ?>
                             </label>
@@ -104,16 +110,19 @@ if ('add-news' == $action && $user->perm->hasPermission($user->getUserId(), 'add
                     </div>
 
                     <div class="form-group row">
                         <label class="col-3 col-form-label" for="link"><?= $PMF_LANG['ad_news_link_url'] ?></label>
                         <div class="col-9">
-                            <input class="form-control" type="text" name="link" id="link" placeholder="http://www.example.com/">
+                            <input class="form-control" type="text" name="link" id="link"
+                            placeholder="http://www.example.com/">
                         </div>
                     </div>
 
                     <div class="form-group row">
-                        <label class="col-3 col-form-label" for="linkTitle"><?= $PMF_LANG['ad_news_link_title'] ?></label>
+                        <label class="col-3 col-form-label" for="linkTitle">
+                        <?= $PMF_LANG['ad_news_link_title'] ?>
+                        </label>
                         <div class="col-9">
                             <input type="text" name="linkTitle" id="linkTitle" class="form-control">
                         </div>
                     </div>
 
@@ -205,11 +214,11 @@ if ('add-news' == $action && $user->perm->hasPermission($user->getUserId(), 'add
     $date = new Date($faqConfig);
     if (count($newsHeader)) {
         foreach ($newsHeader as $newsItem) {
             ?>
                     <tr>
-                        <td><?= $newsItem['header'] ?></td>
+                        <td><?= Strings::htmlentities($newsItem['header']) ?></td>
                         <td><?= $date->format($newsItem['date']) ?></td>
                         <td>
                             <a class="btn btn-primary" href="?action=edit-news&amp;id=<?= $newsItem['id'] ?>">
                                 <span title="<?= $PMF_LANG['ad_news_update'] ?>" class="fa fa-edit"></span>
                             </a>
@@ -252,11 +261,11 @@ if ('add-news' == $action && $user->perm->hasPermission($user->getUserId(), 'add
 
                     <div class="form-group row">
                         <label class="col-3 col-form-label" for="newsheader"><?= $PMF_LANG['ad_news_header'] ?></label>
                         <div class="col-9">
                             <input type="text" name="newsheader" id="newsheader" class="form-control"
-                                   value="<?= $newsData['header'] ?? '' ?>">
+                                   value="<?= Strings::htmlentities($newsData['header']) ?? '' ?>">
                         </div>
                     </div>
 
                     <div class="form-group row">
                         <label class="col-3 col-form-label" for="news"><?= $PMF_LANG['ad_news_text'] ?>:</label>
@@ -268,20 +277,24 @@ if ('add-news' == $action && $user->perm->hasPermission($user->getUserId(), 'add
                             } ?></textarea>
                         </div>
                     </div>
 
                     <div class="form-group row">
-                        <label class="col-3 col-form-label" for="authorName"><?= $PMF_LANG['ad_news_author_name'] ?></label>
+                        <label class="col-3 col-form-label" for="authorName">
+                        <?= $PMF_LANG['ad_news_author_name'] ?>
+                        </label>
                         <div class="col-9">
-                            <input type="text" name="authorName" value="<?= $newsData['authorName'] ?>" class="form-control">
+                            <input type="text" name="authorName" class="form-control"
+                                value="<?= Strings::htmlentities($newsData['authorName']) ?>">
                         </div>
                     </div>
 
                     <div class="form-group row">
                         <label class="col-3 col-form-label" for="authorEmail"><?= $PMF_LANG['ad_news_author_email'] ?></label>
                         <div class="col-9">
-                            <input type="email" name="authorEmail" value="<?= $newsData['authorEmail'] ?>" class="form-control">
+                            <input type="email" name="authorEmail" class="form-control"
+                                value="<?= Strings::htmlentities($newsData['authorEmail']) ?>">
                         </div>
                     </div>
 
                     <div class="form-group row">
                         <label class="col-3 col-form-label" for="active">
@@ -313,19 +326,20 @@ if ('add-news' == $action && $user->perm->hasPermission($user->getUserId(), 'add
                     </div>
 
                     <div class="form-group row">
                         <label class="col-3 col-form-label" for="link"><?= $PMF_LANG['ad_news_link_url'] ?></label>
                         <div class="col-9">
-                            <input type="text" id="link" name="link" value="<?= $newsData['link'] ?>" class="form-control">
+                            <input type="text" id="link" name="link"
+                            value="<?= Strings::htmlentities($newsData['link']) ?>" class="form-control">
                         </div>
                     </div>
 
                     <div class="form-group row">
                         <label class="col-3 col-form-label" for="linkTitle"><?= $PMF_LANG['ad_news_link_title'] ?></label>
                         <div class="col-9">
-                            <input type="text" id="linkTitle" name="linkTitle" value="<?= $newsData['linkTitle'] ?>"
-                            class="form-control">
+                            <input type="text" id="linkTitle" name="linkTitle"
+                            value="<?= Strings::htmlentities($newsData['linkTitle']) ?>" class="form-control">
                         </div>
                     </div>
 
                     <div class="form-group row">
                         <label class="col-3 col-form-label" for="target"><?= $PMF_LANG['ad_news_link_target'] ?></label>
@@ -427,18 +441,18 @@ if ('add-news' == $action && $user->perm->hasPermission($user->getUserId(), 'add
         <div class="row">
             <div class="col-12">
     <?php
     $dateStart = Filter::filterInput(INPUT_POST, 'dateStart', FILTER_UNSAFE_RAW);
     $dateEnd = Filter::filterInput(INPUT_POST, 'dateEnd', FILTER_UNSAFE_RAW);
-    $header = Filter::filterInput(INPUT_POST, 'newsheader', FILTER_UNSAFE_RAW);
+    $header = Filter::filterInput(INPUT_POST, 'newsheader', FILTER_SANITIZE_SPECIAL_CHARS);
     $content = Filter::filterInput(INPUT_POST, 'news', FILTER_SANITIZE_SPECIAL_CHARS);
     $author = Filter::filterInput(INPUT_POST, 'authorName', FILTER_UNSAFE_RAW);
     $email = Filter::filterInput(INPUT_POST, 'authorEmail', FILTER_VALIDATE_EMAIL);
     $active = Filter::filterInput(INPUT_POST, 'active', FILTER_UNSAFE_RAW);
     $comment = Filter::filterInput(INPUT_POST, 'comment', FILTER_UNSAFE_RAW);
-    $link = Filter::filterInput(INPUT_POST, 'link', FILTER_UNSAFE_RAW);
-    $linkTitle = Filter::filterInput(INPUT_POST, 'linkTitle', FILTER_UNSAFE_RAW);
+    $link = Filter::filterInput(INPUT_POST, 'link', FILTER_SANITIZE_SPECIAL_CHARS);
+    $linkTitle = Filter::filterInput(INPUT_POST, 'linkTitle', FILTER_SANITIZE_SPECIAL_CHARS);
     $newsLang = Filter::filterInput(INPUT_POST, 'langTo', FILTER_UNSAFE_RAW);
     $target = Filter::filterInput(INPUT_POST, 'target', FILTER_UNSAFE_RAW);
 
     $newsData = array(
         'lang' => $newsLang,
diff --git a/phpmyfaq/faq.php b/phpmyfaq/faq.php
index a88abf69b6..3b3807fe87 100644
--- a/phpmyfaq/faq.php
+++ b/phpmyfaq/faq.php
@@ -5,17 +5,17 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public License,
  * v. 2.0. If a copy of the MPL was not distributed with this file, You can
  * obtain one at http://mozilla.org/MPL/2.0/.
  *
- * @package phpMyFAQ
- * @author Thorsten Rinne <thorsten@phpmyfaq.de>
- * @author Lars Tiedemann <larstiedemann@yahoo.de>
+ * @package   phpMyFAQ
+ * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
+ * @author    Lars Tiedemann <larstiedemann@yahoo.de>
  * @copyright 2002-2022 phpMyFAQ Team
- * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
- * @link https://www.phpmyfaq.de
- * @since 2002-08-27
+ * @license   http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
+ * @link      https://www.phpmyfaq.de
+ * @since     2002-08-27
  */
 
 use phpMyFAQ\Attachment\AttachmentException;
 use phpMyFAQ\Attachment\AttachmentFactory;
 use phpMyFAQ\Captcha;
@@ -336,11 +336,11 @@ $template->parse(
     'mainPageContent',
     [
         'baseHref' => $faqSystem->getSystemUri($faqConfig),
         'solutionId' => $faq->faqRecord['solution_id'],
         'solutionIdLink' => Link::getSystemRelativeUri() . '?solution_id=' . $faq->faqRecord['solution_id'],
-        'question' => $question,
+        'question' => Strings::htmlentities($question),
         'answer' => $answer,
         'faqDate' => $date->format($faq->faqRecord['date']),
         'faqAuthor' => $author,
         'editThisEntry' => $editThisEntry,
         'msgPdf' => $PMF_LANG['msgPDF'],
diff --git a/phpmyfaq/index.php b/phpmyfaq/index.php
index bb2dba5850..9f449aeb70 100755
--- a/phpmyfaq/index.php
+++ b/phpmyfaq/index.php
@@ -537,11 +537,11 @@ $tplMainPage = [
     'version' => $faqConfig->getVersion(),
     'header' => Strings::htmlspecialchars(str_replace('"', '', $faqConfig->getTitle())),
     'metaTitle' => Strings::htmlspecialchars(str_replace('"', '', $faqConfig->getTitle() . $title)),
     'metaDescription' => Strings::htmlspecialchars($metaDescription ?? ''),
     'metaKeywords' => Strings::htmlspecialchars($keywords),
-    'metaPublisher' => $faqConfig->get('main.metaPublisher'),
+    'metaPublisher' => Strings::htmlspecialchars($faqConfig->get('main.metaPublisher')),
     'metaLanguage' => $PMF_LANG['metaLanguage'],
     'metaRobots' => $faqSeo->getMetaRobots($action),
     'phpmyfaqversion' => $faqConfig->getVersion(),
     'stylesheet' => $PMF_LANG['dir'] == 'rtl' ? 'style.rtl' : 'style',
     'currentPageUrl' => $currentPageUrl,
diff --git a/phpmyfaq/news.php b/phpmyfaq/news.php
index d0e6fe9ac1..dae42e8634 100644
--- a/phpmyfaq/news.php
+++ b/phpmyfaq/news.php
@@ -6,27 +6,28 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public License,
  * v. 2.0. If a copy of the MPL was not distributed with this file, You can
  * obtain one at http://mozilla.org/MPL/2.0/.
  *
- * @package phpMyFAQ
- * @author Thorsten Rinne <thorsten@phpmyfaq.de>
- * @author Matteo Scaramuccia <matteo@scaramuccia.com>
+ * @package   phpMyFAQ
+ * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
+ * @author    Matteo Scaramuccia <matteo@scaramuccia.com>
  * @copyright 2006-2022 phpMyFAQ Team
- * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
- * @link https://www.phpmyfaq.de
- * @since 2006-07-23
+ * @license   http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
+ * @link      https://www.phpmyfaq.de
+ * @since     2006-07-23
  */
 
 use phpMyFAQ\Captcha;
 use phpMyFAQ\Comments;
 use phpMyFAQ\Date;
 use phpMyFAQ\Entity\CommentType;
 use phpMyFAQ\Filter;
 use phpMyFAQ\Glossary;
 use phpMyFAQ\Helper\CaptchaHelper;
 use phpMyFAQ\News;
+use phpMyFAQ\Strings;
 use phpMyFAQ\User\CurrentUser;
 
 if (!defined('IS_VALID_PHPMYFAQ')) {
     http_response_code(400);
     exit();
@@ -72,13 +73,13 @@ $newsHeader = $oGlossary->insertItemsIntoContent($newsHeader);
 // Add information link if existing
 if (strlen($news['link']) > 0) {
     $newsContent .= sprintf(
         '</p><p>%s<a href="%s" target="%s">%s</a>',
         $PMF_LANG['msgInfo'],
-        $news['link'],
+        Strings::htmlentities($news['link']),
         $news['target'],
-        $news['linkTitle']
+        Strings::htmlentities($news['linkTitle'])
     );
 }
 
 // Show link to edit the news?
 $editThisEntry = '';
@@ -119,15 +120,15 @@ $captchaHelper = new CaptchaHelper($faqConfig);
 
 $template->parse(
     'mainPageContent',
     [
         'writeNewsHeader' => $newsMainHeader,
-        'writeHeader' => $newsHeader,
-        'mainPageContent' => $newsContent,
+        'writeHeader' => Strings::htmlentities($newsHeader),
+        'mainPageContent' => Strings::htmlentities($newsContent),
         'writeDateMsg' => $newsDate,
         'msgAboutThisNews' => $PMF_LANG['msgAboutThisNews'],
-        'writeAuthor' => ($news['active'] && (!$expired)) ? $PMF_LANG['msgAuthor'] . ': ' . $news['authorName'] : '',
+        'writeAuthor' => ($news['active'] && (!$expired)) ? $PMF_LANG['msgAuthor'] . ': ' . Strings::htmlentities($news['authorName']) : '',
         'editThisEntry' => $editThisEntry,
         'writeCommentMsg' => $commentMessage,
         'msgWriteComment' => $PMF_LANG['newsWriteComment'],
         'newsId' => $newsId,
         'newsLang' => $news['lang'],
diff --git a/phpmyfaq/src/Bootstrap.php b/phpmyfaq/src/Bootstrap.php
index b364cc0859..a43c284901 100644
--- a/phpmyfaq/src/Bootstrap.php
+++ b/phpmyfaq/src/Bootstrap.php
@@ -23,11 +23,11 @@ use phpMyFAQ\Init;
 
 //
 // Debug mode:
 // - false debug mode disabled
 // - true  debug mode enabled
-const DEBUG = false;
+const DEBUG = true;
 if (DEBUG) {
     ini_set('display_errors', '1');
     ini_set('display_startup_errors', '1');
     error_reporting(-1);
 } else {
diff --git a/phpmyfaq/src/phpMyFAQ/Category.php b/phpmyfaq/src/phpMyFAQ/Category.php
index 90669b0199..824f7bd949 100755
--- a/phpmyfaq/src/phpMyFAQ/Category.php
+++ b/phpmyfaq/src/phpMyFAQ/Category.php
@@ -785,17 +785,17 @@ class Category
             $categoryId
         );
 
         $oLink = new Link($url, $this->config);
         $oLink->id = 'category_' . $categoryId;
-        $oLink->itemTitle = $categoryName;
-        $oLink->text = $categoryName;
+        $oLink->itemTitle = Strings::htmlentities($categoryName);
+        $oLink->text = Strings::htmlentities($categoryName);
 
         if ($hasChildren) {
             $oLink->text .= sprintf(
                 '<i aria-hidden="true" class="fa fa-caret-right" title="%s"></i>',
-                $categoryName
+                Strings::htmlentities($categoryName)
             );
         }
 
         if ($isActive) {
             $oLink->class = 'active';
@@ -888,12 +888,12 @@ class Category
                     $sids,
                     $categoryId[$key]
                 );
                 $oLink = new Link($url, $this->config);
                 $oLink->text = sprintf('<span>%s</span>', $category);
-                $oLink->itemTitle = $category;
-                $oLink->tooltip = $description[$key];
+                $oLink->itemTitle = Strings::htmlentities($category);
+                $oLink->tooltip = Strings::htmlentities($description[$key]);
                 if (0 === $key) {
                     $oLink->setRelation('index');
                 }
 
                 $breadcrumb[] = sprintf(
diff --git a/phpmyfaq/src/phpMyFAQ/Database/DatabaseHelper.php b/phpmyfaq/src/phpMyFAQ/Database/DatabaseHelper.php
index ec73722f6d..64dc72f533 100644
--- a/phpmyfaq/src/phpMyFAQ/Database/DatabaseHelper.php
+++ b/phpmyfaq/src/phpMyFAQ/Database/DatabaseHelper.php
@@ -29,11 +29,11 @@ use phpMyFAQ\Strings;
 class DatabaseHelper
 {
     /**
      * @var Configuration
      */
-    private $config;
+    private Configuration $config;
 
     /**
      * Constructor.
      *
      * @param Configuration $config
diff --git a/phpmyfaq/src/phpMyFAQ/Helper/CategoryHelper.php b/phpmyfaq/src/phpMyFAQ/Helper/CategoryHelper.php
index 0b61c3ab45..68d572b3f2 100644
--- a/phpmyfaq/src/phpMyFAQ/Helper/CategoryHelper.php
+++ b/phpmyfaq/src/phpMyFAQ/Helper/CategoryHelper.php
@@ -239,13 +239,13 @@ class CategoryHelper extends Helper
                     $this->config->getDefaultUrl(),
                     $sids,
                     $parent
                 );
                 $oLink = new Link($url, $this->config);
-                $oLink->itemTitle = $categoryName;
-                $oLink->text = $categoryName;
-                $oLink->tooltip = $description;
+                $oLink->itemTitle = Strings::htmlentities($categoryName);
+                $oLink->text = Strings::htmlentities($categoryName);
+                $oLink->tooltip = !is_null($description) ?? Strings::htmlentities($description);
 
                 $output .= $oLink->toHtmlAnchor();
                 $open = $level;
             }
 
@@ -272,11 +272,11 @@ class CategoryHelper extends Helper
         foreach ($this->Category->categories as $cat) {
             if (0 === (int)$cat['parent_id']) {
                 $categories .= sprintf(
                     '<li><a href="?action=show&cat=%d">%s</a></li>',
                     $cat['id'],
-                    $cat['name']
+                    Strings::htmlentities($cat['name'])
                 );
             }
         }
 
         return $categories;
@@ -321,11 +321,11 @@ class CategoryHelper extends Helper
                     }
                 }
             }
 
             $categories .= '>';
-            $categories .= $indent . $cat['name'] . "</option>\n";
+            $categories .= $indent . Strings::htmlentities($cat['name']) . "</option>\n";
             ++$i;
         }
 
         return $categories;
     }
@@ -353,11 +353,11 @@ class CategoryHelper extends Helper
                 '<div class="card-body">' .
                 '<h4 class="card-title text-center">' .
                 '<a href="' . Strings::htmlentities($category['url']) . '">' .
                 Strings::htmlentities($category['name']) . '</a>' .
                 '</h4>' .
-                '<p class="card-text">' . $category['description'] . '</p>' .
+                '<p class="card-text">' . Strings::htmlentities($category['description']) . '</p>' .
                 '</div>' .
                 '</div>';
             if ($key % 2 === 0) {
                 $decks .= '<div class="w-100 d-none d-sm-block d-md-none"></div>';
             }
@@ -502,13 +502,13 @@ class CategoryHelper extends Helper
                 $this->config->getDefaultUrl(),
                 $sids,
                 $parent
             );
             $oLink = new Link($url, $this->config);
-            $oLink->itemTitle = $categoryName;
-            $oLink->text = $categoryName;
-            $oLink->tooltip = $description;
+            $oLink->itemTitle = Strings::htmlentities($categoryName);
+            $oLink->text = Strings::htmlentities($categoryName);
+            $oLink->tooltip = !is_null($description) ?? Strings::htmlentities($description);
 
             $output .= $oLink->toHtmlAnchor() . $numFaqs;
             $open = $level;
         }
 
diff --git a/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php b/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php
index 70178d9a54..114d5e29cf 100644
--- a/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php
+++ b/phpmyfaq/src/phpMyFAQ/Helper/FaqHelper.php
@@ -161,16 +161,16 @@ class FaqHelper extends Helper
 
     /**
      * Creates an overview with all categories with their FAQs.
      *
      * @param Category $category
-     * @param Faq $faq
-     * @param string $language
+     * @param Faq      $faq
+     * @param string   $language
      * @return string
      * @throws Exception
      */
-    public function createOverview(Category $category, Faq $faq, $language = ''): string
+    public function createOverview(Category $category, Faq $faq, string $language = ''): string
     {
         global $PMF_LANG;
 
         $output = '';
 
@@ -207,12 +207,12 @@ class FaqHelper extends Helper
 
     /**
      * Creates a list of links with available languages to edit a FAQ
      * in the admin backend.
      *
-     * @param  $faqId
-     * @param  $faqLang
+     * @param int    $faqId
+     * @param string $faqLang
      * @return string
      */
     public function createFaqTranslationLinkList(int $faqId, string $faqLang): string
     {
         global $languageCodes;
diff --git a/phpmyfaq/src/phpMyFAQ/Helper/QuestionHelper.php b/phpmyfaq/src/phpMyFAQ/Helper/QuestionHelper.php
index 674a28bdca..131bcb41c4 100644
--- a/phpmyfaq/src/phpMyFAQ/Helper/QuestionHelper.php
+++ b/phpmyfaq/src/phpMyFAQ/Helper/QuestionHelper.php
@@ -29,17 +29,17 @@ use phpMyFAQ\User;
  * @package phpMyFAQ\Helper
  */
 class QuestionHelper
 {
     /** @var Configuration */
-    private $config;
+    private Configuration $config;
 
     /** @var Category */
-    private $category;
+    private Category $category;
 
     /** @var array */
-    private $translation;
+    private array $translation;
 
     /**
      * QuestionHelper constructor.
      * @param Configuration $config
      * @param Category $category
diff --git a/phpmyfaq/src/phpMyFAQ/Helper/TagsHelper.php b/phpmyfaq/src/phpMyFAQ/Helper/TagsHelper.php
index d44c430c66..98a19a5488 100644
--- a/phpmyfaq/src/phpMyFAQ/Helper/TagsHelper.php
+++ b/phpmyfaq/src/phpMyFAQ/Helper/TagsHelper.php
@@ -5,12 +5,11 @@
  *
  * This Source Code Form is subject to the terms of the Mozilla Public License,
  * v. 2.0. If a copy of the MPL was not distributed with this file, You can
  * obtain one at http://mozilla.org/MPL/2.0/.
  *
- * @package    phpMyFAQ\Helper
- * @subpackage TagsHelper
+ * @package    phpMyFAQ
  * @author     Thorsten Rinne <thorsten@phpmyfaq.de>
  * @copyright  2013-2022 phpMyFAQ Team
  * @license    http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
  * @link       https://www.phpmyfaq.de
  * @since      2013-12-26
@@ -18,10 +17,11 @@
 
 namespace phpMyFAQ\Helper;
 
 use phpMyFAQ\Filter;
 use phpMyFAQ\Helper;
+use phpMyFAQ\Strings;
 
 /**
  * Class TagsHelper
  * @package phpMyFAQ\Helper
  */
@@ -30,11 +30,11 @@ class TagsHelper extends Helper
     /**
      * The array of Tag IDs
      *
      * @var array
      */
-    private $taggingIds;
+    private array $taggingIds;
 
     /**
      * Renders the tag list.
      *
      * @param array $tags Array of tags.
@@ -59,43 +59,43 @@ class TagsHelper extends Helper
      *
      * @return string
      */
     public function renderSearchTag(int $tagId, string $tagName): string
     {
-        $taggingIds = str_replace($tagId, '', $this->getTaggingIds());
+        $taggingIds = str_replace((string) $tagId, '', $this->getTaggingIds());
         $taggingIds = str_replace(' ', '', $taggingIds);
         $taggingIds = str_replace(',,', ',', $taggingIds);
         $taggingIds = trim(implode(',', $taggingIds), ',');
 
         return ($taggingIds != '') ? sprintf(
             '<a class="btn btn-primary m-1" href="?action=search&amp;tagging_id=%s">%s ' .
             '<i aria-hidden="true" class="fa fa-minus-square"></i></a> ',
             $taggingIds,
-            $tagName
+            Strings::htmlentities($tagName)
         ) : sprintf(
             '<a class="btn btn-primary m-1" href="?action=search&amp;search=">%s ' .
             '<i aria-hidden="true" class="fa fa-minus-square"></i></a> ',
-            $tagName
+            Strings::htmlentities($tagName)
         );
     }
 
     /**
      * Returns all tag IDs as array.
      *
      * @return array
      */
-    public function getTaggingIds()
+    public function getTaggingIds(): array
     {
         return $this->taggingIds;
     }
 
     /**
      * Sets the tag IDs.
      *
      * @param array $taggingIds The tag IDs as array
      */
-    public function setTaggingIds(array $taggingIds)
+    public function setTaggingIds(array $taggingIds): void
     {
         $this->taggingIds = array_filter($taggingIds, function ($tagId) {
             return Filter::filterVar($tagId, FILTER_VALIDATE_INT);
         });
     }
@@ -115,10 +115,10 @@ class TagsHelper extends Helper
         return sprintf(
             '<a class="btn btn-primary" href="?action=search&amp;tagging_id=%s">%s %s ' .
             '<span class="badge badge-dark">%d</span></a>',
             implode(',', $this->getTaggingIds()) . ',' . $tagId,
             '<i aria-hidden="true" class="fa fa-plus-square"></i> ',
-            $tagName,
+            Strings::htmlentities($tagName),
             $relevance
         );
     }
 }
diff --git a/phpmyfaq/src/phpMyFAQ/News.php b/phpmyfaq/src/phpMyFAQ/News.php
index e37bb8cd6c..b6569b5239 100644
--- a/phpmyfaq/src/phpMyFAQ/News.php
+++ b/phpmyfaq/src/phpMyFAQ/News.php
@@ -57,11 +57,11 @@ class News
      * @param bool $showArchive Show archived news
      * @param bool $active Show active news
      * @return string
      * @throws Exception
      */
-    public function getNews($showArchive = false, $active = true): string
+    public function getNews(bool $showArchive = false, bool $active = true): string
     {
         $output = '';
         $news = $this->getLatestData($showArchive, $active);
         $date = new Date($this->config);
 
@@ -73,19 +73,19 @@ class News
                 $item['lang']
             );
             $oLink = new Link($url, $this->config);
 
             if (isset($item['header'])) {
-                $oLink->itemTitle = $item['header'];
+                $oLink->itemTitle = Strings::htmlentities($item['header']);
             }
 
             $output .= sprintf(
                 '<h6%s><a id="news_%d" href="%s">%s <i aria-hidden="true" class="fa fa-caret-right"></i></a></h6>',
                 ' class="pmf-news-heading"',
                 $item['id'],
                 $oLink->toString(),
-                $item['header']
+                Strings::htmlentities($item['header'])
             );
 
             $output .= sprintf('%s', $item['content']);
 
             if (strlen($item['link']) > 1) {
@@ -301,20 +301,20 @@ class News
             (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')",
             Database::getTablePrefix(),
             $this->config->getDb()->nextId(Database::getTablePrefix() . 'faqnews', 'id'),
             $data['date'],
             $data['lang'],
-            $data['header'],
-            $data['content'],
-            $data['authorName'],
+            $this->config->getDb()->escape($data['header']),
+            $this->config->getDb()->escape($data['content']),
+            $this->config->getDb()->escape($data['authorName']),
             $data['authorEmail'],
             $data['dateStart'],
             $data['dateEnd'],
             $data['active'],
             $data['comment'],
-            $data['link'],
-            $data['linkTitle'],
+            $this->config->getDb()->escape($data['link']),
+            $this->config->getDb()->escape($data['linkTitle']),
             $data['target']
         );
 
         if (!$this->config->getDb()->query($query)) {
             return false;
@@ -353,20 +353,20 @@ class News
             WHERE
                 id = %d",
             Database::getTablePrefix(),
             $data['date'],
             $data['lang'],
-            $data['header'],
-            $data['content'],
-            $data['authorName'],
+            $this->config->getDb()->escape($data['header']),
+            $this->config->getDb()->escape($data['content']),
+            $this->config->getDb()->escape($data['authorName']),
             $data['authorEmail'],
             $data['dateStart'],
             $data['dateEnd'],
             $data['active'],
             $data['comment'],
-            $data['link'],
-            $data['linkTitle'],
+            $this->config->getDb()->escape($data['link']),
+            $this->config->getDb()->escape($data['linkTitle']),
             $data['target'],
             $id
         );
 
         if (!$this->config->getDb()->query($query)) {
diff --git a/phpmyfaq/src/phpMyFAQ/Utils.php b/phpmyfaq/src/phpMyFAQ/Utils.php
index bd966337f1..c4000c7fd7 100644
--- a/phpmyfaq/src/phpMyFAQ/Utils.php
+++ b/phpmyfaq/src/phpMyFAQ/Utils.php
@@ -230,19 +230,19 @@ class Utils
      */
     public static function debug(string $string): string
     {
         // sometimes Zend Optimizer causes segfaults with debug_backtrace()
         if (extension_loaded('Zend Optimizer')) {
-            $ret = '<code>' . $string . "</code><br>\n";
+            $ret = '<code>' . Strings::htmlentities($string) . "</code><br>\n";
         } else {
             $debug = debug_backtrace();
             $ret = '';
             if (isset($debug[2]['class'])) {
                 $ret = $debug[2]['file'] . ':<br>';
                 $ret .= $debug[2]['class'] . $debug[1]['type'];
                 $ret .= $debug[2]['function'] . '() in line ' . $debug[2]['line'];
-                $ret .= ': <code>' . $string . "</code><br>\n";
+                $ret .= ': <code>' . Strings::htmlentities($string) . "</code><br>\n";
             }
         }
 
         return $ret;
     }
diff --git a/phpmyfaq/startpage.php b/phpmyfaq/startpage.php
index 75283f5571..bacb8aa8ba 100755
--- a/phpmyfaq/startpage.php
+++ b/phpmyfaq/startpage.php
@@ -34,10 +34,11 @@ if (!is_null($archived)) {
     $showAllNews = sprintf('<a href="?%s">%s</a>', $sids, $PMF_LANG['newsShowCurrent']);
     $archived = true;
 } else {
     $writeNewsHeader = ' ' . $PMF_LANG['msgNews'];
     $showAllNews = sprintf('<a href="?%snewsid=0">%s</a>', $sids, $PMF_LANG['newsShowArchive']);
+    $archived = false;
 }
 
 $startPageCategories = $category->getHomeCategories();
 if (count($startPageCategories) > 0) {
     $template->parseBlock(

Vulnerable code:                     'name' => Filter::filterInput(INPUT_POST, 'name', FILTER_UNSAFE_RAW),
                    'description' => Filter::filterInput(INPUT_POST, 'description', FILTER_UNSAFE_RAW),
 * @package phpMyFAQ
 * @author Thorsten Rinne <thorsten@phpmyfaq.de>
 * @author Matteo Scaramuccia <matteo@phpmyfaq.de>
 * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
 * @link https://www.phpmyfaq.de
 * @since 2003-02-23
use phpMyFAQ\News;
                        <label class="col-3 col-form-label" for="authorName"><?= $PMF_LANG['ad_news_author_name'] ?></label>
                        <label class="col-3 col-form-label" for="authorEmail"><?= $PMF_LANG['ad_news_author_email'] ?></label>
                        <label class="col-3 col-form-label" for="comment"><?= $PMF_LANG['ad_news_allowComments'] ?></label>
                            <input class="form-control" type="text" name="link" id="link" placeholder="http://www.example.com/">
                        <label class="col-3 col-form-label" for="linkTitle"><?= $PMF_LANG['ad_news_link_title'] ?></label>
                        <td><?= $newsItem['header'] ?></td>
                                   value="<?= $newsData['header'] ?? '' ?>">
                        <label class="col-3 col-form-label" for="authorName"><?= $PMF_LANG['ad_news_author_name'] ?></label>
                            <input type="text" name="authorName" value="<?= $newsData['authorName'] ?>" class="form-control">
                            <input type="email" name="authorEmail" value="<?= $newsData['authorEmail'] ?>" class="form-control">
                            <input type="text" id="link" name="link" value="<?= $newsData['link'] ?>" class="form-control">
                            <input type="text" id="linkTitle" name="linkTitle" value="<?= $newsData['linkTitle'] ?>"
                            class="form-control">
    $header = Filter::filterInput(INPUT_POST, 'newsheader', FILTER_UNSAFE_RAW);
    $link = Filter::filterInput(INPUT_POST, 'link', FILTER_UNSAFE_RAW);
    $linkTitle = Filter::filterInput(INPUT_POST, 'linkTitle', FILTER_UNSAFE_RAW);
 * @package phpMyFAQ
 * @author Thorsten Rinne <thorsten@phpmyfaq.de>
 * @author Lars Tiedemann <larstiedemann@yahoo.de>
 * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
 * @link https://www.phpmyfaq.de
 * @since 2002-08-27
        'question' => $question,
    'metaPublisher' => $faqConfig->get('main.metaPublisher'),
 * @package phpMyFAQ
 * @author Thorsten Rinne <thorsten@phpmyfaq.de>
 * @author Matteo Scaramuccia <matteo@scaramuccia.com>
 * @license http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
 * @link https://www.phpmyfaq.de
 * @since 2006-07-23
        $news['link'],
        $news['linkTitle']
        'writeHeader' => $newsHeader,
        'mainPageContent' => $newsContent,
        'writeAuthor' => ($news['active'] && (!$expired)) ? $PMF_LANG['msgAuthor'] . ': ' . $news['authorName'] : '',
const DEBUG = false;
        $oLink->itemTitle = $categoryName;
        $oLink->text = $categoryName;
                $categoryName
                $oLink->itemTitle = $category;
                $oLink->tooltip = $description[$key];
    private $config;
                $oLink->itemTitle = $categoryName;
                $oLink->text = $categoryName;
                $oLink->tooltip = $description;
                    $cat['name']
            $categories .= $indent . $cat['name'] . "</option>\n";
                '<p class="card-text">' . $category['description'] . '</p>' .
            $oLink->itemTitle = $categoryName;
            $oLink->text = $categoryName;
            $oLink->tooltip = $description;
     * @param Faq $faq
     * @param string $language
    public function createOverview(Category $category, Faq $faq, $language = ''): string
     * @param  $faqId
     * @param  $faqLang
    private $config;
    private $category;
    private $translation;
 * @package    phpMyFAQ\Helper
 * @subpackage TagsHelper
    private $taggingIds;
        $taggingIds = str_replace($tagId, '', $this->getTaggingIds());
            $tagName
            $tagName
    public function getTaggingIds()
    public function setTaggingIds(array $taggingIds)
            $tagName,
    public function getNews($showArchive = false, $active = true): string
                $oLink->itemTitle = $item['header'];
                $item['header']
            $data['header'],
            $data['content'],
            $data['authorName'],
            $data['link'],
            $data['linkTitle'],
            $data['header'],
            $data['content'],
            $data['authorName'],
            $data['link'],
            $data['linkTitle'],
            $ret = '<code>' . $string . "</code><br>\n";
                $ret .= ': <code>' . $string . "</code><br>\n";
Fixed code:                     'name' => Filter::filterInput(INPUT_POST, 'name', FILTER_SANITIZE_SPECIAL_CHARS),
                    'description' => Filter::filterInput(INPUT_POST, 'description', FILTER_SANITIZE_SPECIAL_CHARS),
 * @package   phpMyFAQ
 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
 * @author    Matteo Scaramuccia <matteo@phpmyfaq.de>
 * @license   http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
 * @link      https://www.phpmyfaq.de
 * @since     2003-02-23
use phpMyFAQ\News;use phpMyFAQ\Strings;
                        <label class="col-3 col-form-label" for="authorName">
                        <?= $PMF_LANG['ad_news_author_name'] ?>
                        </label>
                        <label class="col-3 col-form-label" for="authorEmail">
                        <?= $PMF_LANG['ad_news_author_email'] ?>
                        </label>
                        <label class="col-3 col-form-label" for="comment">
                        <?= $PMF_LANG['ad_news_allowComments'] ?>
                        </label>
                            <input class="form-control" type="text" name="link" id="link"
                            placeholder="http://www.example.com/">
                        <label class="col-3 col-form-label" for="linkTitle">
                        <?= $PMF_LANG['ad_news_link_title'] ?>
                        </label>
                        <td><?= Strings::htmlentities($newsItem['header']) ?></td>
                                   value="<?= Strings::htmlentities($newsData['header']) ?? '' ?>">
                        <label class="col-3 col-form-label" for="authorName">
                        <?= $PMF_LANG['ad_news_author_name'] ?>
                        </label>
                            <input type="text" name="authorName" class="form-control"
                                value="<?= Strings::htmlentities($newsData['authorName']) ?>">
                            <input type="email" name="authorEmail" class="form-control"
                                value="<?= Strings::htmlentities($newsData['authorEmail']) ?>">
                            <input type="text" id="link" name="link"
                            value="<?= Strings::htmlentities($newsData['link']) ?>" class="form-control">
                            <input type="text" id="linkTitle" name="linkTitle"
                            value="<?= Strings::htmlentities($newsData['linkTitle']) ?>" class="form-control">
    $header = Filter::filterInput(INPUT_POST, 'newsheader', FILTER_SANITIZE_SPECIAL_CHARS);
    $link = Filter::filterInput(INPUT_POST, 'link', FILTER_SANITIZE_SPECIAL_CHARS);
    $linkTitle = Filter::filterInput(INPUT_POST, 'linkTitle', FILTER_SANITIZE_SPECIAL_CHARS);
 * @package   phpMyFAQ
 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
 * @author    Lars Tiedemann <larstiedemann@yahoo.de>
 * @license   http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
 * @link      https://www.phpmyfaq.de
 * @since     2002-08-27
        'question' => Strings::htmlentities($question),
    'metaPublisher' => Strings::htmlspecialchars($faqConfig->get('main.metaPublisher')),
 * @package   phpMyFAQ
 * @author    Thorsten Rinne <thorsten@phpmyfaq.de>
 * @author    Matteo Scaramuccia <matteo@scaramuccia.com>
 * @license   http://www.mozilla.org/MPL/2.0/ Mozilla Public License Version 2.0
 * @link      https://www.phpmyfaq.de
 * @since     2006-07-23
use phpMyFAQ\Strings;
        Strings::htmlentities($news['link']),
        Strings::htmlentities($news['linkTitle'])
        'writeHeader' => Strings::htmlentities($newsHeader),
        'mainPageContent' => Strings::htmlentities($newsContent),
        'writeAuthor' => ($news['active'] && (!$expired)) ? $PMF_LANG['msgAuthor'] . ': ' . Strings::htmlentities($news['authorName']) : '',
const DEBUG = true;
        $oLink->itemTitle = Strings::htmlentities($categoryName);
        $oLink->text = Strings::htmlentities($categoryName);
                Strings::htmlentities($categoryName)
                $oLink->itemTitle = Strings::htmlentities($category);
                $oLink->tooltip = Strings::htmlentities($description[$key]);
    private Configuration $config;
                $oLink->itemTitle = Strings::htmlentities($categoryName);
                $oLink->text = Strings::htmlentities($categoryName);
                $oLink->tooltip = !is_null($description) ?? Strings::htmlentities($description);
                    Strings::htmlentities($cat['name'])
            $categories .= $indent . Strings::htmlentities($cat['name']) . "</option>\n";
                '<p class="card-text">' . Strings::htmlentities($category['description']) . '</p>' .
            $oLink->itemTitle = Strings::htmlentities($categoryName);
            $oLink->text = Strings::htmlentities($categoryName);
            $oLink->tooltip = !is_null($description) ?? Strings::htmlentities($description);
     * @param Faq      $faq
     * @param string   $language
    public function createOverview(Category $category, Faq $faq, string $language = ''): string
     * @param int    $faqId
     * @param string $faqLang
    private Configuration $config;
    private Category $category;
    private array $translation;
 * @package    phpMyFAQ
use phpMyFAQ\Strings;
    private array $taggingIds;
        $taggingIds = str_replace((string) $tagId, '', $this->getTaggingIds());
            Strings::htmlentities($tagName)
            Strings::htmlentities($tagName)
    public function getTaggingIds(): array
    public function setTaggingIds(array $taggingIds): void
            Strings::htmlentities($tagName),
    public function getNews(bool $showArchive = false, bool $active = true): string
                $oLink->itemTitle = Strings::htmlentities($item['header']);
                Strings::htmlentities($item['header'])
            $this->config->getDb()->escape($data['header']),
            $this->config->getDb()->escape($data['content']),
            $this->config->getDb()->escape($data['authorName']),
            $this->config->getDb()->escape($data['link']),
            $this->config->getDb()->escape($data['linkTitle']),
            $this->config->getDb()->escape($data['header']),
            $this->config->getDb()->escape($data['content']),
            $this->config->getDb()->escape($data['authorName']),
            $this->config->getDb()->escape($data['link']),
            $this->config->getDb()->escape($data['linkTitle']),
            $ret = '<code>' . Strings::htmlentities($string) . "</code><br>\n";
                $ret .= ': <code>' . Strings::htmlentities($string) . "</code><br>\n";
    $archived = false;