CVE-2021-4267: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: A vulnerability classified as problematic was found in tad_discuss. Affected by this vulnerability is an unknown functionality. The manipulation of the argument DiscussTitle leads to cross site scripting. The attack can be launched remotely. The name of the patch is af94d034ff8db642d05fd8788179eab05f433958. It is recommended to apply a patch to fix this issue. The identifier VDB-216469 was assigned to this vulnerability.
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: 2022-12-21T19:15Z
Repository: https://github.com/tad0616/tad_discuss
Language: PHP
Files changed: discuss.php, function.php, index.php
Commit date: 2021-03-23 14:01:56 +0800
Commit message: DiscussTitle過濾特殊字元

DiscussContent若允許使用HTML，則無法避免使用onclick, onload, onerror造成XSS漏洞

Diff: diff --git a/discuss.php b/discuss.php
index 32a0ac1..3c0f095 100644
--- a/discuss.php
+++ b/discuss.php
@@ -372,10 +372,11 @@ function show_one_tad_discuss($DefDiscussID = '')
 
         if (empty($first)) {
             $first = $DiscussContent;
         }
 
+        $discuss['DiscussTitle'] = $myts->htmlSpecialChars($discuss['DiscussTitle']);
         $discuss['DiscussTitle'] = str_replace('[s', "<img src='" . XOOPS_URL . '/modules/tad_discuss/images/smiles/s', $discuss['DiscussTitle']);
         $discuss['DiscussTitle'] = str_replace('.gif]', ".gif' hspace=2 align='absmiddle'>", $discuss['DiscussTitle']);
 
         $DiscussContent = str_replace('[s', "<img src='" . XOOPS_URL . '/modules/tad_discuss/images/smiles/s', $DiscussContent);
         $DiscussContent = str_replace('.gif]', ".gif' hspace=2 align='absmiddle'>", $DiscussContent);
diff --git a/function.php b/function.php
index edbc44b..1c4f270 100644
--- a/function.php
+++ b/function.php
@@ -203,10 +203,11 @@ function saveItem_Permissions($groups, $itemid, $perm_name)
 
 //列出所有tad_discuss資料
 function list_tad_discuss($DefBoardID = null)
 {
     global $xoopsDB, $xoopsModule, $xoopsUser, $xoopsModuleConfig, $isAdmin, $xoopsTpl;
+    $myts = \MyTextSanitizer::getInstance();
     $now_uid = is_object($xoopsUser) ? $xoopsUser->uid() : '0';
 
     //取得本模組編號
     $module_id = $xoopsModule->mid();
 
@@ -282,10 +283,11 @@ function list_tad_discuss($DefBoardID = null)
         $DiscussDate = mb_substr($DiscussDate, 0, 16);
 
         $isPublic = isPublic($onlyTo, $uid, $DefBoardID);
         $onlyToName = getOnlyToName($onlyTo);
 
+        $DiscussTitle = $myts->htmlSpecialChars($DiscussTitle);
         $DiscussTitle = str_replace('[s', "<img src='" . XOOPS_URL . '/modules/tad_discuss/images/smiles/s', $DiscussTitle);
         $DiscussTitle = str_replace('.gif]', ".gif' hspace=2 align='absmiddle'>", $DiscussTitle);
 
         $main_data[$i]['LastTime'] = $LastTime;
         $main_data[$i]['DiscussID'] = $DiscussID;
@@ -530,11 +532,11 @@ function insert_tad_discuss($nl2br = false)
     }
 
     $ReDiscussID = isset($_POST['ReDiscussID']) ? (int) $_POST['ReDiscussID'] : 0;
     //$now=date('Y-m-d H:i:s',xoops_getUserTimestamp(time()));
     $Discuss = get_tad_discuss($ReDiscussID);
-    $DiscussTitle = empty($_POST['DiscussTitle']) ? 'RE:' . $Discuss['DiscussTitle'] : $_POST['DiscussTitle'];
+    $DiscussTitle = empty($_POST['DiscussTitle']) ? 'RE:' . $Discuss['DiscussTitle'] : $myts->addSlashes($_POST['DiscussTitle']);
     $DiscussTitle = $myts->addSlashes($DiscussTitle);
     $publisher = $myts->addSlashes($_POST['publisher']);
     $BoardID = (int) $_POST['BoardID'];
 
     $DiscussContent = $myts->addSlashes($_POST['DiscussContent']);
@@ -581,21 +583,21 @@ function insert_tad_discuss($nl2br = false)
         $xoopsDB->queryF($sql) or Utility::web_error($sql, __FILE__, __LINE__);
         $ToDiscussID = $ReDiscussID;
     }
 
     //全局
-    $extra_tags['DISCUSS_TITLE'] = $_POST['DiscussTitle'];
+    $extra_tags['DISCUSS_TITLE'] = $myts->htmlSpecialChars($_POST['DiscussTitle']);
     $extra_tags['DISCUSS_CONTENT'] = strip_tags($_POST['DiscussContent']);
     $extra_tags['DISCUSS_URL'] = XOOPS_URL . "/modules/tad_discuss/discuss.php?DiscussID={$ToDiscussID}&BoardID={$_POST['BoardID']}";
 
     $notificationHandler = xoops_getHandler('notification');
     $notificationHandler->triggerEvent('global', 0, 'new_discuss', $extra_tags, null, null, 0);
 
     //分類
     if (!empty($_POST['BoardID'])) {
         $Board = get_tad_discuss_board($_POST['BoardID']);
-        $extra_tags['BOARD_TITLE'] = $Board['BoardTitle'];
+        $extra_tags['BOARD_TITLE'] = $myts->htmlSpecialChars($Board['BoardTitle']);
         $notificationHandler = xoops_getHandler('notification');
         $notificationHandler->triggerEvent('board', $_POST['BoardID'], 'new_board_discuss', $extra_tags, null, null, 0);
     }
 
     if (!empty($ReDiscussID)) {
diff --git a/index.php b/index.php
index 20dfc66..bc0735a 100644
--- a/index.php
+++ b/index.php
@@ -92,10 +92,12 @@ function list_tad_discuss_board($ofBoardID = 0, $mode = 'tpl')
 //列出所有tad_discuss資料
 function list_tad_discuss_short($BoardID = null, $limit = null)
 {
     global $xoopsDB, $xoopsModule, $xoopsUser, $xoopsTpl;
 
+    $myts = \MyTextSanitizer::getInstance();
+
     $andBoardID = (empty($BoardID)) ? '' : "and a.BoardID='$BoardID'";
     $andLimit = null !== $limit ? "limit 0,$limit" : '';
     $sql = 'select a.*,b.* from ' . $xoopsDB->prefix('tad_discuss') . ' as a left join ' . $xoopsDB->prefix('tad_discuss_board') . " as b on a.BoardID = b.BoardID where a.ReDiscussID='0' $andBoardID  order by a.LastTime desc $andLimit";
 
     $result = $xoopsDB->query($sql) or Utility::web_error($sql, __FILE__, __LINE__);
@@ -114,11 +116,11 @@ function list_tad_discuss_short($BoardID = null, $limit = null)
         $uid_name = \XoopsUser::getUnameFromId($uid, 1);
         $LastTime = mb_substr($LastTime, 0, 10);
 
         $isPublic = isPublic($onlyTo, $uid, $BoardID);
         $onlyToName = getOnlyToName($onlyTo);
-        $DiscussTitle = $isPublic ? $DiscussTitle : sprintf(_MD_TADDISCUS_ONLYTO, $onlyToName);
+        $DiscussTitle = $isPublic ? $myts->htmlSpecialChars($DiscussTitle) : sprintf(_MD_TADDISCUS_ONLYTO, $onlyToName);
 
         $DiscussTitle = str_replace('[s', "<img src='" . XOOPS_URL . '/modules/tad_discuss/images/smiles/s', $DiscussTitle);
         $DiscussTitle = str_replace('.gif]', ".gif' hspace=2 align='absmiddle'>", $DiscussTitle);
 
         $main_data[$i]['LastTime'] = $LastTime;

Vulnerable code:     $DiscussTitle = empty($_POST['DiscussTitle']) ? 'RE:' . $Discuss['DiscussTitle'] : $_POST['DiscussTitle'];
    $extra_tags['DISCUSS_TITLE'] = $_POST['DiscussTitle'];
        $extra_tags['BOARD_TITLE'] = $Board['BoardTitle'];
        $DiscussTitle = $isPublic ? $DiscussTitle : sprintf(_MD_TADDISCUS_ONLYTO, $onlyToName);
Fixed code:         $discuss['DiscussTitle'] = $myts->htmlSpecialChars($discuss['DiscussTitle']);
    $myts = \MyTextSanitizer::getInstance();
        $DiscussTitle = $myts->htmlSpecialChars($DiscussTitle);
    $DiscussTitle = empty($_POST['DiscussTitle']) ? 'RE:' . $Discuss['DiscussTitle'] : $myts->addSlashes($_POST['DiscussTitle']);
    $extra_tags['DISCUSS_TITLE'] = $myts->htmlSpecialChars($_POST['DiscussTitle']);
        $extra_tags['BOARD_TITLE'] = $myts->htmlSpecialChars($Board['BoardTitle']);
    $myts = \MyTextSanitizer::getInstance();

        $DiscussTitle = $isPublic ? $myts->htmlSpecialChars($DiscussTitle) : sprintf(_MD_TADDISCUS_ONLYTO, $onlyToName);