CVE-2020-17476: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Mibew Messenger before 3.2.7 allows XSS via a crafted user name.
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: 2020-08-10T17:15Z
Repository: https://github.com/Mibew/mibew
Language: PHP
Files changed: src/mibew/libs/chat.php, src/mibew/libs/classes/Mibew/Controller/ButtonController.php, src/mibew/libs/classes/Mibew/Controller/Chat/RedirectController.php, src/mibew/libs/classes/Mibew/RequestProcessor/ThreadProcessor.php, src/mibew/libs/classes/Mibew/Thread.php, src/mibew/libs/invitation.php
Commit date: 2020-07-09 11:16:53 +0300
Commit message: Fix multiple XSS (thanks to adsec2s)

Diff: diff --git a/src/mibew/libs/chat.php b/src/mibew/libs/chat.php
index b1da78e1..5b79fea0 100644
--- a/src/mibew/libs/chat.php
+++ b/src/mibew/libs/chat.php
@@ -695,28 +695,28 @@ function chat_start_for_user(
         $operator_name = get_operator_name($operator);
         $thread->postMessage(
             Thread::KIND_FOR_AGENT,
             getlocal(
                 'Visitor accepted invitation from operator {0}',
-                array($operator_name),
+                array(safe_htmlspecialchars($operator_name)),
                 get_current_locale(),
                 true
             )
         );
     } else {
         if ($referrer) {
             $thread->postMessage(
                 Thread::KIND_FOR_AGENT,
-                getlocal('Visitor came from page {0}', array($referrer), get_current_locale(), true)
+                getlocal('Visitor came from page {0}', array(safe_htmlspecialchars($referrer)), get_current_locale(), true)
             );
         }
         if ($requested_operator && !$requested_operator_online) {
             $thread->postMessage(
                 Thread::KIND_INFO,
                 getlocal(
                     'Thank you for contacting us. We are sorry, but requested operator <strong>{0}</strong> is offline. Another operator will be with you shortly.',
-                    array(get_operator_name($requested_operator)),
+                    array(safe_htmlspecialchars(get_operator_name($requested_operator))),
                     get_current_locale(),
                     true
                 )
             );
         } else {
@@ -729,11 +729,11 @@ function chat_start_for_user(
 
     // TODO: May be move sending this message somewhere else?
     if ($info) {
         $thread->postMessage(
             Thread::KIND_FOR_AGENT,
-            getlocal('Info: {0}', array($info), get_current_locale(), true)
+            getlocal('Info: {0}', array(safe_htmlspecialchars($info)), get_current_locale(), true)
         );
     }
 
     // Let plugins know that user is ready to chat.
     $dispatcher = EventDispatcher::getInstance();
diff --git a/src/mibew/libs/classes/Mibew/Controller/ButtonController.php b/src/mibew/libs/classes/Mibew/Controller/ButtonController.php
index c8828a65..6ec0bc03 100644
--- a/src/mibew/libs/classes/Mibew/Controller/ButtonController.php
+++ b/src/mibew/libs/classes/Mibew/Controller/ButtonController.php
@@ -48,11 +48,11 @@ class ButtonController extends AbstractController
         if ($referer && isset($_SESSION[SESSION_PREFIX . 'threadid']) && $new_page) {
             $thread = Thread::load($_SESSION[SESSION_PREFIX . 'threadid']);
             if ($thread && $thread->state != Thread::STATE_CLOSED) {
                 $msg = getlocal(
                     "Visitor navigated to {0}",
-                    array($referer),
+                    array(safe_htmlspecialchars($referer)),
                     $thread->locale,
                     true
                 );
                 $thread->postMessage(Thread::KIND_FOR_AGENT, $msg);
             }
diff --git a/src/mibew/libs/classes/Mibew/Controller/Chat/RedirectController.php b/src/mibew/libs/classes/Mibew/Controller/Chat/RedirectController.php
index 96bb88a2..36ca0bdd 100644
--- a/src/mibew/libs/classes/Mibew/Controller/Chat/RedirectController.php
+++ b/src/mibew/libs/classes/Mibew/Controller/Chat/RedirectController.php
@@ -179,11 +179,11 @@ class RedirectController extends AbstractController
         // Send notification message
         $thread->postMessage(
             Thread::KIND_EVENTS,
             getlocal(
                 'Operator {0} redirected you to another operator. Please wait a while.',
-                array(get_operator_name($this->getOperator())),
+                array(safe_htmlspecialchars(get_operator_name($this->getOperator()))),
                 $thread->locale,
                 true
             )
         );
 
@@ -233,11 +233,11 @@ class RedirectController extends AbstractController
         // Send notification message
         $thread->postMessage(
             Thread::KIND_EVENTS,
             getlocal(
                 'Operator {0} redirected you to another operator. Please wait a while.',
-                array(get_operator_name($this->getOperator())),
+                array(safe_htmlspecialchars(get_operator_name($this->getOperator()))),
                 $thread->locale,
                 true
             )
         );
 
diff --git a/src/mibew/libs/classes/Mibew/RequestProcessor/ThreadProcessor.php b/src/mibew/libs/classes/Mibew/RequestProcessor/ThreadProcessor.php
index 7f930229..b281ece7 100644
--- a/src/mibew/libs/classes/Mibew/RequestProcessor/ThreadProcessor.php
+++ b/src/mibew/libs/classes/Mibew/RequestProcessor/ThreadProcessor.php
@@ -669,11 +669,11 @@ class ThreadProcessor extends ClientSideProcessor implements
 
         // Send some messages
         if ($email) {
             $thread->postMessage(
                 Thread::KIND_FOR_AGENT,
-                getlocal('E-Mail: {0}', array($email), get_current_locale(), true)
+                getlocal('E-Mail: {0}', array(safe_htmlspecialchars($email)), get_current_locale(), true)
             );
         }
 
         if ($first_message) {
             $posted_id = $thread->postMessage(
@@ -788,23 +788,23 @@ class ThreadProcessor extends ClientSideProcessor implements
 
         // Send some messages
         if ($referrer) {
             $thread->postMessage(
                 Thread::KIND_FOR_AGENT,
-                getlocal('Visitor came from page {0}', array($referrer), get_current_locale(), true)
+                getlocal('Visitor came from page {0}', array(safe_htmlspecialchars($referrer)), get_current_locale(), true)
             );
         }
         if ($email) {
             $thread->postMessage(
                 Thread::KIND_FOR_AGENT,
-                getlocal('E-Mail: {0}', array($email), get_current_locale(), true)
+                getlocal('E-Mail: {0}', array(safe_htmlspecialchars($email)), get_current_locale(), true)
             );
         }
         if ($info) {
             $thread->postMessage(
                 Thread::KIND_FOR_AGENT,
-                getlocal('Info: {0}', array($info), get_current_locale(), true)
+                getlocal('Info: {0}', array(safe_htmlspecialchars($info)), get_current_locale(), true)
             );
         }
         $thread->postMessage(Thread::KIND_USER, $message, array('name' => $name));
 
         // Get email for message
diff --git a/src/mibew/libs/classes/Mibew/Thread.php b/src/mibew/libs/classes/Mibew/Thread.php
index 8132cc89..0d5ccfb9 100644
--- a/src/mibew/libs/classes/Mibew/Thread.php
+++ b/src/mibew/libs/classes/Mibew/Thread.php
@@ -756,18 +756,18 @@ class Thread
         if ($this->state == self::STATE_WAITING && $is_operator_correct) {
             // Prepare message
             if ($this->nextAgent == $operator['operatorid']) {
                 $message_to_post = getlocal(
                     "Operator <strong>{0}</strong> changed operator <strong>{1}</strong>",
-                    array($operator_name, $this->agentName),
+                    array(safe_htmlspecialchars($operator_name), safe_htmlspecialchars($this->agentName)),
                     $this->locale,
                     true
                 );
             } else {
                 $message_to_post = getlocal(
                     "Operator {0} is back",
-                    array($operator_name),
+                    array(safe_htmlspecialchars($operator_name)),
                     $this->locale,
                     true
                 );
             }
 
@@ -924,11 +924,11 @@ class Thread
         if ($is_user) {
             $this->postMessage(
                 self::KIND_EVENTS,
                 getlocal(
                     "Visitor {0} left the chat",
-                    array($this->userName),
+                    array(safe_htmlspecialchars($this->userName)),
                     $this->locale,
                     true
                 )
             );
         } else {
@@ -945,11 +945,11 @@ class Thread
             } else {
                 $this->postMessage(
                     self::KIND_EVENTS,
                     getlocal(
                         "Operator {0} left the chat",
-                        array($this->agentName),
+                        array(safe_htmlspecialchars($this->agentName)),
                         $this->locale,
                         true
                     )
                 );
             }
@@ -1023,25 +1023,25 @@ class Thread
             : $operator['vccommonname'];
 
         if ($is_operator_changed) {
             $message = getlocal(
                 "Operator <strong>{0}</strong> changed operator <strong>{1}</strong>",
-                array($operator_name, $this->agentName),
+                array(safe_htmlspecialchars($operator_name), safe_htmlspecialchars($this->agentName)),
                 $this->locale,
                 true
             );
         } elseif ($is_operator_joined) {
             $message = getlocal(
                 "Operator {0} joined the chat",
-                array($operator_name),
+                array(safe_htmlspecialchars($operator_name)),
                 $this->locale,
                 true
             );
         } elseif ($is_operator_back) {
             $message = getlocal(
                 "Operator {0} is back",
-                array($operator_name),
+                array(safe_htmlspecialchars($operator_name)),
                 $this->locale,
                 true
             );
         }
 
@@ -1081,11 +1081,11 @@ class Thread
             $this->save();
 
             // Send message about renaming
             $message = getlocal(
                 "The visitor changed their name <strong>{0}</strong> to <strong>{1}</strong>",
-                array($old_name, $new_name),
+                array(safe_htmlspecialchars($old_name), safe_htmlspecialchars($new_name)),
                 $this->locale,
                 true
             );
             $this->postMessage(self::KIND_EVENTS, $message);
         }
diff --git a/src/mibew/libs/invitation.php b/src/mibew/libs/invitation.php
index aac10f84..ca5ba69c 100644
--- a/src/mibew/libs/invitation.php
+++ b/src/mibew/libs/invitation.php
@@ -123,11 +123,11 @@ function invitation_invite($visitor_id, $operator)
     // Send some messages
     $thread->postMessage(
         Thread::KIND_FOR_AGENT,
         getlocal(
             'Operator {0} invites visitor at {1} page',
-            array($operator_name, $last_visited_page),
+            array(safe_htmlspecialchars($operator_name), safe_htmlspecialchars($last_visited_page)),
             get_current_locale(),
             true
         )
     );
     $thread->postMessage(

Vulnerable code:                 array($operator_name),
                getlocal('Visitor came from page {0}', array($referrer), get_current_locale(), true)
                    array(get_operator_name($requested_operator)),
            getlocal('Info: {0}', array($info), get_current_locale(), true)
                    array($referer),
                array(get_operator_name($this->getOperator())),
                array(get_operator_name($this->getOperator())),
                getlocal('E-Mail: {0}', array($email), get_current_locale(), true)
                getlocal('Visitor came from page {0}', array($referrer), get_current_locale(), true)
                getlocal('E-Mail: {0}', array($email), get_current_locale(), true)
                getlocal('Info: {0}', array($info), get_current_locale(), true)
                    array($operator_name, $this->agentName),
                    array($operator_name),
                    array($this->userName),
                        array($this->agentName),
                array($operator_name, $this->agentName),
                array($operator_name),
                array($operator_name),
                array($old_name, $new_name),
            array($operator_name, $last_visited_page),
Fixed code:                 array(safe_htmlspecialchars($operator_name)),
                getlocal('Visitor came from page {0}', array(safe_htmlspecialchars($referrer)), get_current_locale(), true)
                    array(safe_htmlspecialchars(get_operator_name($requested_operator))),
            getlocal('Info: {0}', array(safe_htmlspecialchars($info)), get_current_locale(), true)
                    array(safe_htmlspecialchars($referer)),
                array(safe_htmlspecialchars(get_operator_name($this->getOperator()))),
                array(safe_htmlspecialchars(get_operator_name($this->getOperator()))),
                getlocal('E-Mail: {0}', array(safe_htmlspecialchars($email)), get_current_locale(), true)
                getlocal('Visitor came from page {0}', array(safe_htmlspecialchars($referrer)), get_current_locale(), true)
                getlocal('E-Mail: {0}', array(safe_htmlspecialchars($email)), get_current_locale(), true)
                getlocal('Info: {0}', array(safe_htmlspecialchars($info)), get_current_locale(), true)
                    array(safe_htmlspecialchars($operator_name), safe_htmlspecialchars($this->agentName)),
                    array(safe_htmlspecialchars($operator_name)),
                    array(safe_htmlspecialchars($this->userName)),
                        array(safe_htmlspecialchars($this->agentName)),
                array(safe_htmlspecialchars($operator_name), safe_htmlspecialchars($this->agentName)),
                array(safe_htmlspecialchars($operator_name)),
                array(safe_htmlspecialchars($operator_name)),
                array(safe_htmlspecialchars($old_name), safe_htmlspecialchars($new_name)),
            array(safe_htmlspecialchars($operator_name), safe_htmlspecialchars($last_visited_page)),