Skip to content

Fix ruff FURB189: use UserDict instead of dict subclass

6a30549
Select commit
Loading
Failed to load commit list.
Merged

Add centralized banner system with OS messaging support #14708

Fix ruff FURB189: use UserDict instead of dict subclass
6a30549
Select commit
Loading
Failed to load commit list.
DryRunSecurity / Cross-Site Scripting Analyzer succeeded Apr 18, 2026 in 7s

DryRun Security

Details

Cross-Site Scripting Analyzer Findings: 3 detected

⚠️ Potential Cross-Site Scripting dojo/context_processors.py (click for details)
Type Potential Cross-Site Scripting
Description additional_banners may include data from two sources: (1) get_os_banner() which fetches remote Markdown, renders it to HTML via markdown.markdown and then sanitizes with bleach.clean into 'message' and 'expanded_html'; (2) arbitrary dicts stored in request.session by product_announcement.add_session_banner (message field created from str((message))) and later popped and added directly to context. The template renders banner.message and banner.expanded_html with the
Filename dojo/context_processors.py
CodeLink
"DOCUMENTATION_URL": settings.DOCUMENTATION_URL,
"API_TOKENS_ENABLED": settings.API_TOKENS_ENABLED,
"API_TOKEN_AUTH_ENDPOINT_ENABLED": settings.API_TOKEN_AUTH_ENDPOINT_ENABLED,
"SHOW_PLG_LINK": True,
# V3 Feature Flags
"V3_FEATURE_LOCATIONS": settings.V3_FEATURE_LOCATIONS,
}
additional_banners = []
if (os_banner := get_os_banner()) is not None:
additional_banners.append({
"source": "os",
"message": os_banner["message"],
"style": "info",
"url": "",
"link_text": "",
"expanded_html": os_banner["expanded_html"],
})
if hasattr(request, "session"):
for banner in request.session.pop("_product_banners", []):
additional_banners.append(banner)
if additional_banners:
context["additional_banners"] = additional_banners
return context
def bind_system_settings(request):
"""Load system settings and display warning if there's a database error."""
⚠️ Potential Cross-Site Scripting dojo/product_announcements.py (click for details)
Type Potential Cross-Site Scripting
Description mark_safe is used when building a session banner message: mark_safe(f"{self.base_message} {self.ui_outreach}") — this bypasses Django auto-escaping. If any interpolated content can be attacker-controlled, it would reach a template and be rendered without escaping, causing XSS.
Filename dojo/product_announcements.py
CodeLink
message=mark_safe(f"{self.base_message} {self.ui_outreach}"),
)
⚠️ Potential Cross-Site Scripting dojo/templates/base.html (click for details)
Type Potential Cross-Site Scripting
Description Template uses the safe filter to render banner.message and banner.expanded_html ({{ banner.message
Filename dojo/templates/base.html
CodeLink
{% for banner in additional_banners %}
<div role="alert" class="announcement-banner alert alert-{{ banner.style }} show"
data-source="{{ banner.source }}">
{{ banner.message|safe }}{% if banner.url %} <a href="{{ banner.url }}">{{ banner.link_text }}</a>{% endif %}
{% if banner.expanded_html %}
<button type="button" class="banner-toggle collapsed"
data-toggle="collapse"
data-target="#banner-expanded-{{ forloop.counter }}"
aria-expanded="false"
aria-controls="banner-expanded-{{ forloop.counter }}">
<i class="fa-solid fa-caret-down"></i>
</button>
<div id="banner-expanded-{{ forloop.counter }}" class="collapse banner-expanded">
{{ banner.expanded_html|safe }}
</div>
{% endif %}
</div>
{% endfor %}