CVE-2023-33186: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: Zulip is an open-source team collaboration tool with unique topic-based threading that combines the best of email and chat to make remote work productive and delightful. The main development branch of Zulip Server from May 2, 2023 and later, including beta versions 7.0-beta1 and 7.0-beta2, is vulnerable to a cross-site scripting vulnerability in tooltips on the message feed. An attacker who can send messages could maliciously craft a topic for the message, such that a victim who hovers the tooltip for that topic in their message feed triggers execution of JavaScript code controlled by the attacker.
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-05-30T06:16Z
Repository: https://github.com/zulip/zulip
Language: Other
Files changed: web/src/tippyjs.js, web/templates/narrow_tooltip.hbs, web/templates/tooltip_templates.hbs
Commit date: 2023-05-29 16:35:49 -0700
Commit message: CVE-2023-33186: Fix topic tooltip cross-site scripting vulnerability.

Commit 903dbda79bd176702d3175a7c8a5450a64b6eccb (#25370) introduced a
cross-site scripting vulnerability in the tooltips for the stream and
topic in the recipient bar.  An attacker who can send messages could
maliciously craft a topic for the message, such that a victim who
hovers the tooltip for that topic in their message feed triggers
execution of JavaScript code controlled by the attacker.

Signed-off-by: Anders Kaseorg <anders@zulip.com>

Diff: diff --git a/web/src/tippyjs.js b/web/src/tippyjs.js
index 0272e43203d..4bfee8d0fd9 100644
--- a/web/src/tippyjs.js
+++ b/web/src/tippyjs.js
@@ -2,10 +2,11 @@ import $ from "jquery";
 import _ from "lodash";
 import tippy, {delegate} from "tippy.js";
 
 import render_message_inline_image_tooltip from "../templates/message_inline_image_tooltip.hbs";
 import render_narrow_to_compose_recipients_tooltip from "../templates/narrow_to_compose_recipients_tooltip.hbs";
+import render_narrow_tooltip from "../templates/narrow_tooltip.hbs";
 import render_tooltip_templates from "../templates/tooltip_templates.hbs";
 
 import * as compose_recipient from "./compose_recipient";
 import * as compose_state from "./compose_state";
 import {$t} from "./i18n";
@@ -187,12 +188,13 @@ export function initialize() {
     });
 
     message_list_tooltip(".tippy-narrow-tooltip", {
         delay: LONG_HOVER_DELAY,
         onCreate(instance) {
-            const content = instance.props.content + $("#narrow-hotkey-tooltip-template").html();
-            instance.setContent(parse_html(content));
+            instance.setContent(
+                parse_html(render_narrow_tooltip({content: instance.props.content})),
+            );
         },
     });
 
     delegate("body", {
         target: ".toggle-subscription-tooltip",
diff --git a/web/templates/narrow_tooltip.hbs b/web/templates/narrow_tooltip.hbs
new file mode 100644
index 00000000000..21b268af65c
--- /dev/null
+++ b/web/templates/narrow_tooltip.hbs
@@ -0,0 +1,2 @@
+{{content}}
+{{tooltip_hotkey_hints "S"}}
diff --git a/web/templates/tooltip_templates.hbs b/web/templates/tooltip_templates.hbs
index c7bdfad96a9..55208191c24 100644
--- a/web/templates/tooltip_templates.hbs
+++ b/web/templates/tooltip_templates.hbs
@@ -1,12 +1,9 @@
 <template id="view-user-card-tooltip-template">
     {{t 'View user card' }}
     {{tooltip_hotkey_hints "U"}}
 </template>
-<template id="narrow-hotkey-tooltip-template">
-    {{tooltip_hotkey_hints "S"}}
-</template>
 <template id="compose_draft_tooltip_template">
     {{t 'Drafts' }}
     {{tooltip_hotkey_hints "D"}}
 </template>
 <template id="scroll-to-bottom-button-tooltip-template">

Vulnerable code:             const content = instance.props.content + $("#narrow-hotkey-tooltip-template").html();
            instance.setContent(parse_html(content));
<template id="narrow-hotkey-tooltip-template">
    {{tooltip_hotkey_hints "S"}}
</template>
Fixed code: import render_narrow_tooltip from "../templates/narrow_tooltip.hbs";
            instance.setContent(
                parse_html(render_narrow_tooltip({content: instance.props.content})),
            );
{{content}}
{{tooltip_hotkey_hints "S"}}