diff --git a/backend/app/services/email_service.py b/backend/app/services/email_service.py index fb2f3c19d..937adfdd6 100644 --- a/backend/app/services/email_service.py +++ b/backend/app/services/email_service.py @@ -2,6 +2,7 @@ from __future__ import annotations +import html import logging import re import secrets @@ -85,8 +86,8 @@ def render_template(template_str: str, variables: dict[str, Any]) -> str: result = template_str for key, value in variables.items(): result = result.replace("{" + key + "}", str(value) if value is not None else "") - # Remove any remaining unreplaced placeholders - result = re.sub(r"\{[a-z_]+\}", "", result) + # Remove any remaining unreplaced placeholders (case-insensitive, alphanumeric + underscore) + result = re.sub(r"\{[a-zA-Z0-9_]+\}", "", result) return result @@ -416,6 +417,8 @@ async def create_welcome_email_from_template( text_body = render_template(template.body_template, variables) # Create HTML version with embedded login button + # Escape text_body to prevent XSS vulnerabilities + escaped_text_body = html.escape(text_body) html_body = f""" @@ -424,10 +427,10 @@ async def create_welcome_email_from_template(
-

{subject}

+

{html.escape(subject)}

-
{text_body}
+
{escaped_text_body}
Login Now @@ -476,6 +479,8 @@ async def create_password_reset_email_from_template( text_body = render_template(template.body_template, variables) # Create HTML version with embedded login button + # Escape text_body to prevent XSS vulnerabilities + escaped_text_body = html.escape(text_body) html_body = f""" @@ -484,10 +489,10 @@ async def create_password_reset_email_from_template(
-

{subject}

+

{html.escape(subject)}

-
{text_body}
+
{escaped_text_body}
Login Now