How Horilla Protects Against Cross-Site Scripting (XSS) Attacks
Security is a top priority in modern web applications, and Cross-Site Scripting (XSS) remains one of the most common vulnerabilities targeted by attackers. At Horilla HRMS, we’ve taken deliberate steps to safeguard our system from these threats, starting from the model layer itself.
In this blog, we’ll explore how Horilla protects against XSS attacks using Django’s model validation capabilities, coupled with our custom logic.
What Is an XSS Attack?
Cross-Site Scripting (XSS) is a type of vulnerability where attackers inject malicious scripts (typically JavaScript) into content that is then rendered by the browser. If not handled properly, these scripts can:
- Steal user session cookies
- Redirect users to malicious sites
- Deface pages or mislead users
- Hijack user interactions
Our Defense Strategy
Horilla implements an XSS detection mechanism right within the core or abstract model layer, making sure that malicious scripts are never stored in the database in the first place.
Here’s a breakdown of our strategy.
Step 1: Validate Input Before Saving
All models in Horilla that extend from HorillaModel inherit a secure save() method:
def save(self, *args, **kwargs):
"""
Override the save method to automatically run full model validation.
"""
self.full_clean()
super().save(*args, **kwargs)
...
This ensures that before anything is saved to the database, Django’s validation system (including our custom validations) is executed.
Step 2: Detect and Block XSS Patterns
We use a custom has_xss function that looks for common XSS injection patterns in string fields:
import re
def has_xss(value):
"""Basic check for common XSS patterns."""
if not isinstance(value, str):
return False
xss_pattern = re.compile(r"<.*?script.*?>|javascript:|on\w+=", re.IGNORECASE)
return bool(xss_pattern.search(value))
This function checks for:
- <script> tags
- Inline event handlers like onclick=
- javascript: URLs
These patterns are among the most common vectors used in XSS attacks.
Step 3: Clean Fields with XSS Check
We override the clean_fields method in HorillaModel to automatically scan CharField and TextField values:
def clean_fields(self, exclude=None):
errors = {}
# Allow exemptions for specific fields if needed
total_exclude = set(exclude or []).union(getattr(self, "xss_exempt_fields", []))
for field in self._meta.get_fields():
if (
isinstance(field, (models.CharField, models.TextField))
and field.name not in total_exclude
):
value = getattr(self, field.name, None)
if value and has_xss(value):
errors[field.name] = ValidationError(
"Potential XSS content detected."
)
if errors:
raise ValidationError(errors)
This makes it impossible to accidentally persist dangerous content through standard Django model saves unless explicitly exempted.
Extensible & Flexible
In rare cases where a field legitimately needs to accept HTML or JavaScript (e.g., admin-defined templates), developers can mark them as safe using the xss_exempt_fields attribute:
class EmailTemplate(HorillaModel):
content = models.TextField()
xss_exempt_fields = ['content']
This maintains security without compromising flexibility.
Secure by Design
By integrating XSS protection directly into the model layer:
- We prevent bad data at the source.
- Developers don’t need to remember to sanitize every form or API endpoint individually.
- We ensure a consistent security policy across the entire Horilla codebase.
Conclusion
Horilla’s built-in XSS detection mechanism is a testament to our “secure by design” philosophy. By embedding security directly into the foundation of our application—at the model layer—we ensure that vulnerabilities like Cross-Site Scripting (XSS) are proactively detected and blocked before they can ever impact our users.
This approach goes beyond traditional input validation. It provides a centralized, automated defense system that eliminates the risk of human error during development. Developers don’t need to write custom sanitization logic for every form or endpoint, because Horilla’s core logic is already doing the heavy lifting behind the scenes.
As a result, Horilla:
- Protects your data from being corrupted by malicious input.
- Safeguards users from script injections that could compromise their privacy or security.
- Reduces attack surfaces by maintaining strict validation standards across all input sources.
- Builds trust by showing our commitment to secure software practices from day one.
