From 904210f3168a9ec6f499351b8415c90f02d0c08c Mon Sep 17 00:00:00 2001
From: "google-labs-jules[bot]"
<161369871+google-labs-jules[bot]@users.noreply.github.com>
Date: Wed, 11 Mar 2026 04:37:39 +0000
Subject: [PATCH] fix(security): sanitize user inputs rendered as HTML
Sanitizes filenames in file, video, and audio media types as well as display_name and user_id in invited room previews before passing them to the html rendering engine to prevent XSS vulnerabilities.
Co-authored-by: kevinaboos <1139460+kevinaboos@users.noreply.github.com>
---
src/home/room_screen.rs | 6 +++---
src/home/rooms_list_entry.rs | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/home/room_screen.rs b/src/home/room_screen.rs
index dc42a462..0b163415 100644
--- a/src/home/room_screen.rs
+++ b/src/home/room_screen.rs
@@ -3784,7 +3784,7 @@ fn populate_file_message_content(
file_content: &FileMessageEventContent,
) -> bool {
// Display the file name, human-readable size, caption, and a button to download it.
- let filename = file_content.filename();
+ let filename = htmlize::escape_text(file_content.filename());
let size = file_content
.info
.as_ref()
@@ -3814,7 +3814,7 @@ fn populate_audio_message_content(
audio: &AudioMessageEventContent,
) -> bool {
// Display the file name, human-readable size, caption, and a button to download it.
- let filename = audio.filename();
+ let filename = htmlize::escape_text(audio.filename());
let (duration, mime, size) = audio
.info
.as_ref()
@@ -3855,7 +3855,7 @@ fn populate_video_message_content(
video: &VideoMessageEventContent,
) -> bool {
// Display the file name, human-readable size, caption, and a button to download it.
- let filename = video.filename();
+ let filename = htmlize::escape_text(video.filename());
let (duration, mime, size, dimensions) = video
.info
.as_ref()
diff --git a/src/home/rooms_list_entry.rs b/src/home/rooms_list_entry.rs
index 093c1680..dbe78fd3 100644
--- a/src/home/rooms_list_entry.rs
+++ b/src/home/rooms_list_entry.rs
@@ -348,8 +348,8 @@ impl RoomsListEntryContent {
// Hide the timestamp field, and use the latest message field to show the inviter.
self.view.label(ids!(timestamp)).set_text(cx, "");
let inviter_string = match &room_info.inviter_info {
- Some(InviterInfo { user_id, display_name: Some(dn), .. }) => format!("Invited by {dn} ({user_id})"),
- Some(InviterInfo { user_id, .. }) => format!("Invited by {user_id}"),
+ Some(InviterInfo { user_id, display_name: Some(dn), .. }) => format!("Invited by {} ({})", htmlize::escape_text(dn), htmlize::escape_text(user_id.as_str())),
+ Some(InviterInfo { user_id, .. }) => format!("Invited by {}", htmlize::escape_text(user_id.as_str())),
None => String::from("You were invited"),
};
self.view.html_or_plaintext(ids!(latest_message)).show_html(cx, &inviter_string);