[IMP] HORILLA: Stored Cross-Site Scripting Validation
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user