CVE-2022-4902: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: A vulnerability classified as problematic has been found in eXo Chat Application. Affected is an unknown function of the file application/src/main/webapp/vue-app/components/ExoChatMessageComposer.vue of the component Mention Handler. The manipulation leads to cross site scripting. It is possible to launch the attack remotely. Upgrading to version 3.3.0-20220417 is able to address this issue. The name of the patch is 26bf307d3658d1403cfd5c3ad423ce4c4d1cb2dc. It is recommended to upgrade the affected component. The identifier of this vulnerability is VDB-220212.
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: 2023-02-06T19:15Z
Repository: https://github.com/exoplatform/chat-application
Language: Other
Files changed: application/src/main/webapp/vue-app/components/ExoChatMessageComposer.vue
Commit date: 2022-04-15 14:58:26 +0200
Commit message: Task-56304 : XSS issue in chat

Before this fix, when sending a message with a mention, there is an XSS issue
This commit encode html entities in the message before adding markup related to the mention so that, the malicious html is not evaluated
Diff: diff --git a/application/src/main/webapp/vue-app/components/ExoChatMessageComposer.vue b/application/src/main/webapp/vue-app/components/ExoChatMessageComposer.vue
index 240944af..1c8c8cf4 100644
--- a/application/src/main/webapp/vue-app/components/ExoChatMessageComposer.vue
+++ b/application/src/main/webapp/vue-app/components/ExoChatMessageComposer.vue
@@ -338,10 +338,11 @@ export default {
       elem.scrollTop = elem.scrollHeight;
     },
     checkMention(message) {
       message = $('<div />').html(message).text();
       message = message.replace(/\s\s+/g, ' ');
+      message = this.encodeHTMLEntities(message);
       for (let i = 0; i < this.participants.length; i++) {
         if (message.includes(`@${this.participants[i].fullname}`) ){
           this.mentionedUsers.push(this.participants[i].name);
           const profil = chatServices.getUserProfileLink(this.participants[i].name);
           const html = `<a href='${profil}' target='_blank'>@${this.participants[i].fullname}</a>`;
@@ -350,10 +351,15 @@ export default {
       }
       chatServices.sendMentionNotification(this.contact.room, this.contact.fullName, this.mentionedUsers);
       this.mentionedUsers = [];
       return message;
     },
+    encodeHTMLEntities(text) {
+      const textArea = document.createElement('p');
+      textArea.innerText = text;
+      return textArea.innerHTML;
+    },
     paste(e) {
       // consider the first item (can be easily extended for multiple items)
       const item = e.clipboardData.items[0];
       //test if the type of item e
       if (item.type.indexOf('image') === 0) {
@@ -365,13 +371,13 @@ export default {
         reader.readAsDataURL(pastedImage);
       } else {
         // cancel paste
         e.preventDefault();
         // get text representation of clipboard
-        this.text = (e.originalEvent || e).clipboardData.getData('text/plain');
+        this.text = this.encodeHTMLEntities((e.originalEvent || e).clipboardData.getData('text/plain'));
         // insert text manually
         $(this.$refs.messageComposerArea).insertAtCaret(this.text);
       }
     },
   }
 };
-</script>
\ No newline at end of file
+</script>

Vulnerable code:         this.text = (e.originalEvent || e).clipboardData.getData('text/plain');
</script>
Fixed code:       message = this.encodeHTMLEntities(message);
    encodeHTMLEntities(text) {
      const textArea = document.createElement('p');
      textArea.innerText = text;
      return textArea.innerHTML;
    },
        this.text = this.encodeHTMLEntities((e.originalEvent || e).clipboardData.getData('text/plain'));
</script>