Interactive Playground
Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.
pathfinder scan --ruleset python/PYTHON-DJANGO-SEC-053 --project .About This Rule
Understanding the vulnerability and how it is detected
This audit rule flags all class definitions that extend SafeString or SafeData from django.utils.safestring. Classes that inherit from SafeString are treated as pre-validated safe HTML by Django's template engine, bypassing automatic escaping when their instances are rendered in templates.
SafeString is the internal type returned by mark_safe() and format_html(). It is designed for use within Django's own utilities, not as a base class for application code. Subclassing SafeString is an unusual pattern that bypasses auto-escaping at the class inheritance level, meaning all instances and operations on instances inherit the "safe" designation.
This rule surfaces all such subclasses for security review to verify that the class does not allow user-controlled data to flow through without escaping, and that the subclassing is intentional and justified.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Inherited Safety Bypass for All Instances
Unlike mark_safe() which marks a specific string value as safe, subclassing SafeString marks the entire class as safe. Any string operation on a SafeString subclass instance that incorporates user-controlled content will produce an output that is treated as safe by the template engine, potentially rendering XSS payloads without escaping.
String Operations Propagate Safety Flag
SafeString overrides string concatenation and other operations such that SafeString + regular_string returns a SafeString. This means user input concatenated onto a SafeString subclass instance inherits the safety flag and is rendered without escaping in templates.
Widespread Impact from Shared Types
SafeString subclasses are often used as shared utility types across the application. A vulnerability in the class definition affects every view, template, and component that uses that type, potentially exposing the entire application to XSS.
Difficult-to-Audit Safety Inheritance
SafeString subclassing creates implicit auto-escaping bypass that is not obvious at template rendering time. Unlike mark_safe() which appears inline where the unsafe content is introduced, SafeString inheritance separates the escape bypass declaration from the template rendering site by potentially many files and call stacks.
How to Fix
Recommended remediation steps
- 1Avoid subclassing SafeString or SafeData in application code; use mark_safe() or format_html() at the specific point where content is validated to be safe instead.
- 2If a SafeString subclass is unavoidable, ensure the constructor validates all input against an allowlist or escapes all user-controlled values before calling super().__new__().
- 3Review all string operations on SafeString subclass instances to ensure user-controlled strings are never concatenated onto them without prior escaping.
- 4Consider replacing SafeString subclasses with plain classes that have a render() method using format_html(), which makes the escaping explicit and local.
- 5Add unit tests for SafeString subclasses that verify HTML-special characters in constructor arguments are properly escaped in the output.
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule uses QueryType pattern matching rather than taint analysis. It matches all class definitions where the base class is SafeString or SafeData (checked via DjangoClasses.extends("SafeString") and DjangoClasses.extends("SafeData")). This is an audit rule providing visibility for manual review. Use PYTHON-DJANGO-SEC-050 for taint-based XSS detection in CI. The .where() clause constrains matches to Python files in Django project structures.
Compliance & Standards
Industry frameworks and regulations that require detection of this vulnerability
References
External resources and documentation
Similar Rules
Explore related security rules for Python
Django XSS via Direct HttpResponse with User Input
User input flows directly to HttpResponse without HTML escaping, enabling Cross-Site Scripting (XSS) attacks.
Django mark_safe() Usage Audit
mark_safe() bypasses Django's automatic HTML escaping. Audit all usages to confirm content is properly sanitized before being marked safe.
Django XSS in HTML Email Body via EmailMessage
User input flows into HTML email body content without sanitization, enabling HTML injection in emails.
Frequently Asked Questions
Common questions about Django SafeString Subclass Audit
New feature
Get these findings posted directly on your GitHub pull requests
The Django SafeString Subclass Audit rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.