[IMP] HORILLA: Stored Cross-Site Scripting Validation

This commit is contained in:
Horilla
2025-05-19 10:41:07 +05:30
parent 8760d14848
commit f4ed2978f4
2 changed files with 39 additions and 0 deletions

View File

@@ -8,9 +8,12 @@ the application, such as tracking creation and modification timestamps and user
information, audit logging, and active/inactive status management.
"""
import re
from auditlog.models import AuditlogHistoryField
from auditlog.registry import auditlog
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models.fields.files import FieldFile
from django.urls import reverse
@@ -34,6 +37,14 @@ def url(self: FieldFile):
setattr(FieldFile, "url", url)
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))
class HorillaModel(models.Model):
"""
An abstract base model that includes common fields and functionalities
@@ -80,6 +91,8 @@ class HorillaModel(models.Model):
Override the save method to automatically set the created_by and
modified_by fields based on the current request user.
"""
self.full_clean()
request = getattr(_thread_locals, "request", None)
if request:
@@ -99,6 +112,26 @@ class HorillaModel(models.Model):
super(HorillaModel, self).save(*args, **kwargs)
def clean_fields(self, exclude=None):
errors = {}
# Get the list of fields to exclude from validation
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)
def get_verbose_name(self):
return self._meta.verbose_name

View File

@@ -75,6 +75,12 @@ class MailAutomation(HorillaModel):
condition = models.TextField()
xss_exempt_fields = [
"condition_html",
"condition",
"condition_querystring",
]
def save(self, *args, **kwargs):
if not self.pk:
self.method_title = self.title.replace(" ", "_").lower()