.agents/skills/sentry-security/references/output-sanitization.md
User-controlled strings (display names, team names, org names) rendered in email templates can contain HTML that gets interpreted by email clients.
User display names in invite and team access request emails were not sanitized. An attacker could set their display name to HTML that would render in the recipient's email client.
Vulnerable pattern:
# User display name inserted directly into email context
context = {
"requester_name": requesting_user.get_display_name(),
# ... rendered in HTML email template without escaping
}
Fixed pattern:
from django.utils.html import escape
context = {
"requester_name": escape(requesting_user.get_display_name()),
}
Any code that puts user-provided strings into email context:
get_display_name(), get_username(), name fieldsSearch pattern:
grep -rn "get_display_name\|get_username\|\.name" --include="*.py" src/sentry/notifications/
grep -rn "get_display_name\|get_username\|\.name" --include="*.py" src/sentry/mail/
The markdown renderer allowed custom CSS through <style> tags, enabling CSS-based attacks.
What to check:
<style>, <script>, or <iframe> tags allowed?mark_safe() called on markdown output without sanitization?# WRONG: String concatenation — XSS if user_name contains HTML
html = f"<p>Hello {user_name}</p>"
return mark_safe(html)
# RIGHT: format_html escapes parameters
from django.utils.html import format_html
html = format_html("<p>Hello {}</p>", user_name)
mark_safe() should never be called on strings containing user input. Search for:
grep -rn "mark_safe" --include="*.py" src/sentry/
Flag any usage where the string argument includes user-controlled data.
□ User display names are escaped before use in email templates
□ Team/org/project names are escaped in email context
□ Markdown renderer strips HTML tags (especially style, script, iframe)
□ mark_safe() is never called on user-provided data
□ format_html() is used instead of string concatenation for HTML