CVE-2023-0792: Improper Control of Generation of Code ('Code Injection') (CWE-94)
value: Code Injection in GitHub repository thorsten/phpmyfaq prior to 3.1.11.


CWE description: The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
CVSS v3 base score: 5.4
Published: 2023-02-12T14:15Z
Repository: https://github.com/thorsten/phpmyfaq
Language: PHP
Files changed: phpmyfaq/admin/assets/js/tags.js, phpmyfaq/admin/tags.php
Commit date: 2023-01-23 10:53:29 +0100
Commit message: fix: added missing conversion to HTML entities

Diff: diff --git a/phpmyfaq/admin/assets/js/tags.js b/phpmyfaq/admin/assets/js/tags.js
index 1cc214cacb..87e4f75337 100644
--- a/phpmyfaq/admin/assets/js/tags.js
+++ b/phpmyfaq/admin/assets/js/tags.js
@@ -34,10 +34,14 @@ document.addEventListener('DOMContentLoaded', () => {
     const input = $('input[data-tag-id]:focus');
     const id = input.data('tag-id');
     const tag = input.val();
     const csrf = $('input[name=csrf]').val();
 
+    const escape = (unsafe) => {
+      return unsafe.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&#039;');
+    }
+
     $.ajax({
       url: 'index.php?action=ajax&ajax=tags&ajaxaction=update',
       type: 'POST',
       data: 'id=' + id + '&tag=' + tag + '&csrf=' + csrf,
       dataType: 'json',
@@ -45,11 +49,11 @@ document.addEventListener('DOMContentLoaded', () => {
         $('#pmf-admin-saving-data-indicator').html(
           '<i class="fa fa-cog fa-spin fa-fw"></i><span class="sr-only">Saving ...</span>'
         );
       },
       success: function (message) {
-        input.replaceWith('<span data-tag-id="' + id + '">' + input.val().replace(/\//g, '&#x2F;') + '</span>');
+        input.replaceWith('<span data-tag-id="' + id + '">' + escape(input.val().replace(/\//g, '&#x2F;')) + '</span>');
         $('span[data-tag-id="' + id + '"]');
         $('#pmf-admin-saving-data-indicator').html(message);
       },
     });
 
diff --git a/phpmyfaq/admin/tags.php b/phpmyfaq/admin/tags.php
index 6122e75c82..ceb2b941ec 100644
--- a/phpmyfaq/admin/tags.php
+++ b/phpmyfaq/admin/tags.php
@@ -53,20 +53,20 @@ if (!defined('IS_VALID_PHPMYFAQ')) {
                 }
             }
 
             $tagData = $tags->getAllTags();
 
-            if (count($tagData)) {
+            if (count($tagData) === 0) {
               printf('<p class="alert alert-warning" role="alert">%s</p>', $PMF_LANG['ad_news_nodata']);
             }
 
             echo '<table class="table table-hover">';
             echo '<tbody>';
 
             foreach ($tagData as $key => $tag) {
                 echo '<tr>';
-                echo '<td><span data-tag-id="' . $key . '">' . Strings::htmlspecialchars($tag) . '</span></td>';
+                echo '<td><span data-tag-id="' . $key . '">' . Strings::htmlentities($tag) . '</span></td>';
                 printf(
                     '<td><a class="btn btn-primary btn-edit" data-btn-id="%d" title="%s">' .
                     '<i aria-hidden="true" class="fa fa-edit"></i></a></td>',
                     $key,
                     $PMF_LANG['ad_user_edit']

Vulnerable code:         input.replaceWith('<span data-tag-id="' + id + '">' + input.val().replace(/\//g, '&#x2F;') + '</span>');
            if (count($tagData)) {
                echo '<td><span data-tag-id="' . $key . '">' . Strings::htmlspecialchars($tag) . '</span></td>';
Fixed code:     const escape = (unsafe) => {
      return unsafe.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&#039;');
    }

        input.replaceWith('<span data-tag-id="' + id + '">' + escape(input.val().replace(/\//g, '&#x2F;')) + '</span>');
            if (count($tagData) === 0) {
                echo '<td><span data-tag-id="' . $key . '">' . Strings::htmlentities($tag) . '</span></td>';