diff --git a/pyproject.toml b/pyproject.toml
index 6952302f1a..8de62e8968 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -508,7 +508,7 @@ ignore = [
]
[tool.ruff.lint.flake8-bandit]
-allowed-markup-calls = ["lxml.html.tostring"]
+allowed-markup-calls = ["bs4.BeautifulSoup.decode", "lxml.html.tostring"]
[tool.ruff.lint.flake8-gettext]
extend-function-names = ["gettext_lazy"]
diff --git a/zerver/lib/email_notifications.py b/zerver/lib/email_notifications.py
index 748a0d807c..926459e3c9 100644
--- a/zerver/lib/email_notifications.py
+++ b/zerver/lib/email_notifications.py
@@ -219,11 +219,13 @@ def build_message_list(
return re.sub(r"\[(\S*)\]\((\S*)\)", r"\2", content)
def prepend_sender_to_message(
- message_plain: str, message_html: str, sender: str
- ) -> tuple[str, str]:
+ message_plain: str, message_html: Markup, sender: str
+ ) -> tuple[str, Markup]:
message_plain = f"{sender}:\n{message_plain}"
message_soup = BeautifulSoup(message_html, "html.parser")
- sender_name_soup = BeautifulSoup(f"{sender}: ", "html.parser")
+ sender_name_soup = BeautifulSoup(
+ Markup("{sender}: ").format(sender=sender), "html.parser"
+ )
first_tag = message_soup.find()
if first_tag and first_tag.name == "div":
first_tag = first_tag.find()
@@ -231,9 +233,11 @@ def build_message_list(
first_tag.insert(0, sender_name_soup)
else:
message_soup.insert(0, sender_name_soup)
- return message_plain, str(message_soup)
+ return message_plain, Markup(BeautifulSoup.decode(message_soup))
- def build_message_payload(message: Message, sender: str | None = None) -> dict[str, str]:
+ def build_message_payload(
+ message: Message, sender: str | None = None
+ ) -> dict[str, str | Markup]:
plain = message.content
plain = fix_plaintext_image_urls(plain)
# There's a small chance of colliding with non-Zulip URLs containing
@@ -252,7 +256,7 @@ def build_message_list(
fix_spoilers_in_html(fragment, user.default_language)
change_katex_to_raw_latex(fragment)
- html = lxml.html.tostring(fragment, encoding="unicode")
+ html = Markup(lxml.html.tostring(fragment, encoding="unicode"))
if sender:
plain, html = prepend_sender_to_message(plain, html, sender)
return {"plain": plain, "html": html}