CVE-2022-0374 (PHP, published 2022-01-26T10:15Z)
Description: value: Cross-site Scripting (XSS) - Stored in Packagist remdex/livehelperchat prior to 3.93v.
Severity: LOW (CVSS v3 base score: 5.4)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
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.
Repository: https://github.com/livehelperchat/livehelperchat
Files changed:
lhc_web/design/defaulttheme/tpl/lhchat/lists/msg_obj_list.tpl.php
lhc_web/design/defaulttheme/tpl/lhchat/lists/msg_obj_list_admin.tpl.php
lhc_web/design/defaulttheme/tpl/lhchat/messagelist/plain.tpl.php
lhc_web/design/defaulttheme/tpl/lhform/collected.tpl.php
lhc_web/design/defaulttheme/tpl/lhtheme/admincss.tpl.php
lhc_web/design/defaulttheme/tpl/lhtheme/adminthemeedit.tpl.php
Commit message: fx #1734


Vulnerable code:
<?php 

foreach ($messages as $msg ) : if ($msg->user_id > -1 || $msg->user_id == -2) : 
if ($lastOperatorId !== false && $lastOperatorId != $msg->user_id) {
    $lastOperatorChanged = true;
} else {
    $lastOperatorChanged = false;
}
$lastOperatorId = $msg->user_id;
if ($msg->meta_msg != '') {
    $metaMessageData = json_decode($msg->meta_msg, true); $messageId = $msg->id;
} else if (isset($metaMessageData)) {
    unset($metaMessageData);
}
?>
<div class="message-row<?php echo $msg->user_id == 0 ? ' response' : ' message-admin'.($lastOperatorChanged == true ? ' operator-changes' : '')?>" id="msg-<?php echo $msg->id?>"><div class="msg-date"><?php echo date(erLhcoreClassModule::$dateDateHourFormat,$msg->time);?></div><span class="usr-tit<?php echo $msg->user_id == 0 ? ' vis-tit' : ' op-tit'?>"><?php echo $msg->user_id == 0 ? htmlspecialchars($chat->nick) : htmlspecialchars($msg->name_support) ?>:&nbsp;</span>
    <?php $msgBody = $msg->msg; $paramsMessageRender = array('sender' => $msg->user_id);?>
    <?php include(erLhcoreClassDesign::designtpl('lhchat/lists/msg_body.tpl.php'));?>
    <?php if (isset($metaMessageData)) : ?>
        <?php include(erLhcoreClassDesign::designtpl('lhgenericbot/message/meta_render.tpl.php'));?>
    <?php endif; ?>
</div>
<?php endif; endforeach; ?>
<?php 

$lastOperatorChanged = false;
$lastOperatorId = false;
$lastOperatorNick = '';

foreach ($messages as $msg) : 

if ($lastOperatorId !== false && ($lastOperatorId != $msg->user_id || $lastOperatorNick != $msg->name_support)) {
    $lastOperatorChanged = true;
    $lastOperatorNick = $msg->name_support;
} else {
    $lastOperatorChanged = false;

$lastOperatorId = $msg->user_id;

    if ($msg->meta_msg != '') {
        $metaMessageData = json_decode($msg->meta_msg, true); $messageId = $msg->id;
    } else if (isset($metaMessageData)) {
        unset($metaMessageData);
    }

<?php if ($msg->user_id == -1) : ?>
	<div class="message-row system-response" id="msg-<?php echo $msg->id?>"><div class="msg-date"><?php echo date(erLhcoreClassModule::$dateDateHourFormat,$msg->time);?></div><i><span class="usr-tit sys-tit"><?php echo erTranslationClassLhTranslation::getInstance()->getTranslation('chat/syncadmin','System assistant')?></span><?php echo erLhcoreClassBBCode::make_clickable(htmlspecialchars($msg->msg))?></i></div>
<?php else : ?>
    <?php if ($msg->msg != '' ||
        isset($metaMessageData['content']['text_conditional']) ||
        isset($metaMessageData['content']['chat_operation']) ||
        isset($metaMessageData['content']['html']['content']) ||
        isset($metaMessageData['content']['button_message'])
    ) : ?>
        <div class="message-row<?php echo $msg->user_id == 0 ? ' response' : ' message-admin'.($lastOperatorChanged == true ? ' operator-changes' : '')?>" id="msg-<?php echo $msg->id?>"><div class="msg-date"><?php echo date(erLhcoreClassModule::$dateDateHourFormat,$msg->time);?></div><span class="usr-tit<?php echo $msg->user_id == 0 ? ' vis-tit' : ' op-tit'?>"><?php if ($msg->user_id == 0) : ?><i class="material-icons"><?php echo ($chat->device_type == 0 ? 'computer' : ($chat->device_type == 1 ? 'smartphone' : 'tablet'))?></i><?php endif;?><?php echo $msg->user_id == 0 ? htmlspecialchars($chat->nick) : htmlspecialchars($msg->name_support) ?></span>
            <?php $msgBody = $msg->msg; $paramsMessageRender = array('sender' => $msg->user_id, 'html_as_text' => true);?>
            <?php include(erLhcoreClassDesign::designtpl('lhchat/lists/msg_body.tpl.php'));?>

            <?php if (isset($metaMessageData)) : ?>
                <?php include(erLhcoreClassDesign::designtpl('lhgenericbot/message/meta_render_admin.tpl.php'));?>
            <?php endif; ?>
            
        </div>
    <?php endif;?>
<?php endif;?>
<?php endforeach;?>
<?php foreach ($messages as $msg ) : ?><?php if (!isset($remove_meta) || $remove_meta == false ) :?>[<?php echo date(erLhcoreClassModule::$dateDateHourFormat,$msg->time);?>] [<?php echo $msg->user_id == 0 ? htmlspecialchars($chat->nick) : htmlspecialchars($msg->name_support) ?>] <?php endif;?><?php echo erLhcoreClassBBCodePlain::make_clickable($msg->msg, array('sender' => $msg->user_id)),"\n"?><?php endforeach; ?>
<h1><?php echo htmlspecialchars($form)?></h1>
<table class="table" cellpadding="0" cellspacing="0">
    div.message-admin div.msg-body{
<div class="row">
    <?php /*?><div class="col-2">
        <a class="btn btn-secondary" href="?export=1"><i class="material-icons mr-0">file_download</i></a>
    </div>*/ ?>

Fixed code:
<?php
$lastOperatorNick = '';
$messagesStats = array(
    'total_messages' => count($messages),
    'counter_messages' => 0,
);
foreach ($messages as $msg) :
    $msg = $msg->getState();
    $messagesStats['counter_messages']++;
    if ($lastOperatorId !== false && ($lastOperatorId != $msg['user_id'] || $msg['name_support'] != $lastOperatorNick)) {
        $lastOperatorChanged = true;
        $lastOperatorNick = $msg['name_support'];
    } else {
        $lastOperatorChanged = false;
    }
    $lastOperatorId = $msg['user_id'];
    $lastOperatorNick = $msg['name_support'];
    ?>
    <?php include(erLhcoreClassDesign::designtpl('lhchat/lists/user_msg_row.tpl.php'));?>
<?php endforeach; ?>
<?php
$messagesDefault = [];
foreach ($messages as $msg) {
    $messagesDefault[] = $msg->getState();
$messages = $messagesDefault;
<?php include(erLhcoreClassDesign::designtpl('lhchat/syncadmin.tpl.php'));?>
<?php foreach ($messages as $msg ) :

    if (isset($msg->meta_msg) && $msg->meta_msg != '') {
        $metaMessageData = json_decode($msg->meta_msg, true); $messageId = isset($triggerMessageId) ? $triggerMessageId : $msg->id;
    } else if (isset($metaMessageData)) {
        unset($metaMessageData);
    }

    if (isset($metaMessageData['content']['whisper']) || empty($msg->msg)) {
        continue;
    }

    ?><?php if (!isset($remove_meta) || $remove_meta == false ) :?>[<?php echo date(erLhcoreClassModule::$dateDateHourFormat,$msg->time);?>] [<?php echo $msg->user_id == 0 ? htmlspecialchars($chat->nick) : htmlspecialchars($msg->name_support) ?>] <?php endif;?><?php echo erLhcoreClassBBCodePlain::make_clickable($msg->msg, array('sender' => $msg->user_id)),"\n"?><?php endforeach; ?>
<h1 ng-non-bindable><?php echo htmlspecialchars($form)?></h1>
<table class="table" cellpadding="0" cellspacing="0" ng-non-bindable>
    div.message-admin:not(.whisper-msg) div.msg-body{
<div class="row" ng-non-bindable>