CVE-2023-30609 (Other, published 2023-04-25T21:15Z)
Description: value: matrix-react-sdk is a react-based SDK for inserting a Matrix chat/VoIP client into a web page. Prior to version 3.71.0, plain text messages containing HTML tags are rendered as HTML in the search results. To exploit this, an attacker needs to trick a user into searching for a specific message containing an HTML injection payload. No cross-site scripting attack is possible due to the hardcoded content security policy. Version 3.71.0 of the SDK patches over the issue. As a workaround, restarting the client will clear the HTML injection.
Severity: nan (CVSS v3 base score: 4.7)
Weakness: CWE-74 \u2014 Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
Repository: https://github.com/matrix-org/matrix-react-sdk
Files changed:
src/HtmlUtils.tsx
src/components/views/rooms/SearchResultTile.tsx
test/HtmlUtils-test.tsx
Commit message: Merge pull request from GHSA-xv83-x443-7rmw

* Escape HTML for plaintext search results

* Add tests

Vulnerable code:
     * apply the highlights to a section of text
     *     to.
        let offset;
    returnString: false | undefined;
            safeBody = highlighter.applyHighlights(plainBody, safeHighlights!).join("");
            let highlights;
import React from "react";
import { topicToHtml } from "../src/HtmlUtils";
describe("HtmlUtils", () => {

Fixed code:
import escapeHtml from "escape-html";
     * Apply the highlights to a section of text
     *     to. This input must be sanitised as it will be treated as HTML.
        let offset: number;
    returnString?: false | undefined;
            safeBody = highlighter.applyHighlights(escapeHtml(plainBody), safeHighlights!).join("");
            let highlights: string[] | undefined;
import React, { ReactElement } from "react";
import { IContent } from "matrix-js-sdk/src/models/event";
import { bodyToHtml, topicToHtml } from "../src/HtmlUtils";
describe("topicToHtml", () => {

describe("bodyToHtml", () => {
    function getHtml(content: IContent, highlights?: string[]): string {
        return (bodyToHtml(content, highlights, {}) as ReactElement).props.dangerouslySetInnerHTML.__html;
    }

    it("should apply highlights to HTML messages", () => {
        const html = getHtml(
            {
                body: "test **foo** bar",
                msgtype: "m.text",
                formatted_body: "test <b>foo</b> bar",
                format: "org.matrix.custom.html",
            },
            ["test"],
        );

        expect(html).toMatchInlineSnapshot(`"<span class="mx_EventTile_searchHighlight">test</span> <b>foo</b> bar"`);
    });

    it("should apply highlights to plaintext messages", () => {
        const html = getHtml(
            {
                body: "test foo bar",
                msgtype: "m.text",
            },
            ["test"],
        );

        expect(html).toMatchInlineSnapshot(`"<span class="mx_EventTile_searchHighlight">test</span> foo bar"`);
    });

    it("should not respect HTML tags in plaintext message highlighting", () => {
        const html = getHtml(
            {
                body: "test foo <b>bar",
                msgtype: "m.text",
            },
            ["test"],
        );

        expect(html).toMatchInlineSnapshot(`"<span class="mx_EventTile_searchHighlight">test</span> foo &lt;b&gt;bar"`);
    });
});