diff --git a/base/models.py b/base/models.py index 4b05f28ca..81a5f5d7d 100644 --- a/base/models.py +++ b/base/models.py @@ -1176,7 +1176,6 @@ class HorillaMailTemplate(HorillaModel): verbose_name=_("Company"), ) objects = HorillaCompanyManager(related_company_field="company_id") - xss_exempt_fields = ["body"] def __str__(self) -> str: return f"{self.title}" diff --git a/biometric/templates/biometric/biometric_device_form.html b/biometric/templates/biometric/biometric_device_form.html index f96613783..383edb23c 100644 --- a/biometric/templates/biometric/biometric_device_form.html +++ b/biometric/templates/biometric/biometric_device_form.html @@ -175,4 +175,4 @@ } }); }); - \ No newline at end of file + diff --git a/helpdesk/models.py b/helpdesk/models.py index 03e946ab8..3e9b6f3bd 100644 --- a/helpdesk/models.py +++ b/helpdesk/models.py @@ -204,7 +204,6 @@ class Comment(HorillaModel): Employee, on_delete=models.DO_NOTHING, related_name="employee_comment" ) date = models.DateTimeField(auto_now_add=True) - xss_exempt_fields = ["comment"] # 850 def __str__(self): return self.comment diff --git a/horilla/models.py b/horilla/models.py index 5f889840c..dcc6f93d6 100644 --- a/horilla/models.py +++ b/horilla/models.py @@ -39,12 +39,21 @@ def url(self: FieldFile): setattr(FieldFile, "url", url) -def has_xss(value): - """Basic check for common XSS patterns.""" +def has_xss(value: str) -> bool: + """Detect common XSS attempts (script tags, event handlers, js URLs).""" if not isinstance(value, str): return False - xss_pattern = re.compile(r"<.*?script.*?>|javascript:|on\w+=", re.IGNORECASE) - return bool(xss_pattern.search(value)) + + xss_patterns = [ + r"<\s*script.*?>.*?<\s*/\s*script\s*>", + r"javascript\s*:", + r"on\w+\s*=", + r"<\s*script.*?>.*?(eval|setTimeout|setInterval|new\s+Function|XMLHttpRequest|fetch|\$\s*\().*?<\s*/\s*script\s*>", + r"on\w+\s*=\s*['\"]?\s*(eval|setTimeout|setInterval|new\s+Function|XMLHttpRequest|fetch|\$\s*\()[^>]*", + ] + + combined = re.compile("|".join(xss_patterns), re.IGNORECASE | re.DOTALL) + return bool(combined.search(value)) def upload_path(instance, filename): diff --git a/recruitment/models.py b/recruitment/models.py index 0ed1fe9ad..602912cb6 100644 --- a/recruitment/models.py +++ b/recruitment/models.py @@ -200,7 +200,6 @@ class Recruitment(HorillaModel): help_text=_("Resume not mandatory for candidate creation"), verbose_name=_("Optional Resume"), ) - xss_exempt_fields = ["description"] # 807 class Meta: """