CVE-2022-24799: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: wire-webapp is the web application interface for the wire messaging service. Insufficient escaping in markdown “code highlighting” in the wire-webapp resulted in the possibility of injecting and executing arbitrary HTML code and thus also JavaScript. If a user receives and views such a malicious message, arbitrary code is injected and executed in the context of the victim. This allows the attacker to fully control the user account. Wire-desktop clients that are connected to a vulnerable wire-webapp version are also vulnerable to this attack. The issue has been fixed in wire-webapp 2022-03-30-production.0 and is already deployed on all Wire managed services. On-premise instances of wire-webapp need to be updated to docker tag 2022-03-30-production.0-v0.29.2-0-d144552 or wire-server 2022-03-30 (chart/4.8.0), so that their applications are no longer affected. There are no known workarounds for this issue. ### Patches * The issue has been fixed in wire-webapp **2022-03-30-production.0** and is already deployed on all Wire managed services. * On-premise instances of wire-webapp need to be updated to docker tag **2022-03-30-production.0-v0.29.2-0-d144552** or wire-server **2022-03-30 (chart/4.8.0)**, so that their applications are no longer affected. ### Workarounds * No workarounds known ### For more information If you have any questions or comments about this advisory feel free to email us at [vulnerability-report@wire.com](mailto:vulnerability-report@wire.com) ### Credits We thank [Posix](https://twitter.com/po6ix) for reporting 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-04-20T18:15Z
Repository: https://github.com/wireapp/wire-webapp
Language: TypeScript
Files changed: src/script/util/messageRenderer.ts
Commit date: 2022-03-30 14:33:46 +0200
Commit message: fix: Improve message rendering (#12748)


Diff: diff --git a/src/script/util/messageRenderer.ts b/src/script/util/messageRenderer.ts
index 9f919572a0..c37cda9cfd 100644
--- a/src/script/util/messageRenderer.ts
+++ b/src/script/util/messageRenderer.ts
@@ -136,21 +136,21 @@ export const renderMessage = (message: string, selfId: QualifiedId | null, menti
         return code.includes(hash);
       });
       if (containsMentions) {
         // disable code highlighting if there is a mention in there
         // highlighting will be wrong anyway because this is not valid code
-        return code;
+        return escape(code);
       }
       return hljs.highlightAuto(code).value;
     },
   });
 
   markdownit.renderer.rules.link_open = (tokens, idx, options, env, self) => {
     const cleanString = (hashedString: string) =>
       escape(
         Object.entries(mentionTexts).reduce(
-          (text, [mentionHash, mention]) => text.replace(mentionHash, mention.text),
+          (text, [mentionHash, mention]) => text.replace(mentionHash, () => mention.text),
           hashedString,
         ),
       );
     const link = tokens[idx];
     const href = cleanString(link.attrGet('href'));
@@ -212,11 +212,11 @@ export const renderMessage = (message: string, selfId: QualifiedId | null, menti
   mentionlessText = mentionlessText.replace(/(<br>|\n)*$/, '');
 
   const parsedText = Object.keys(mentionTexts).reduce((text, mentionHash) => {
     const mentionMarkup = renderMention(mentionTexts[mentionHash]);
 
-    return text.replace(mentionHash, mentionMarkup);
+    return text.replace(mentionHash, () => mentionMarkup);
   }, mentionlessText);
   return parsedText;
 };
 
 export const getRenderedTextContent = (text: string): string => {

Vulnerable code:         return code;
          (text, [mentionHash, mention]) => text.replace(mentionHash, mention.text),
    return text.replace(mentionHash, mentionMarkup);
Fixed code:         return escape(code);
          (text, [mentionHash, mention]) => text.replace(mentionHash, () => mention.text),
    return text.replace(mentionHash, () => mentionMarkup);