From: shamoon <4887959+shamoon@users.noreply.github.com>
Date: Fri, 12 Dec 2025 22:01:56 +0000 (-0800)
Subject: Fix: allow safe
+
+ """
+
+ svg_file = BytesIO(malicious_svg)
+ svg_file.name = "cdata_style.svg"
+
+ response = self.client.patch(
+ f"{self.ENDPOINT}1/",
+ {"app_logo": svg_file},
+ format="multipart",
+ )
+ self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
+ self.assertIn("disallowed", str(response.data).lower())
+
def test_api_rejects_svg_with_style_import(self):
"""
GIVEN:
@@ -326,6 +355,36 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
+ def test_api_accepts_valid_svg_with_safe_style_tag(self):
+ """
+ GIVEN:
+ - A valid SVG logo with an embedded
+
+
+ """
+
+ svg_file = BytesIO(safe_svg)
+ svg_file.name = "safe_logo_with_style.svg"
+
+ response = self.client.patch(
+ f"{self.ENDPOINT}1/",
+ {"app_logo": svg_file},
+ format="multipart",
+ )
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+
def test_api_rejects_svg_with_disallowed_attribute(self):
"""
GIVEN:
diff --git a/src/paperless/validators.py b/src/paperless/validators.py
index c1dd652981..bb741df416 100644
--- a/src/paperless/validators.py
+++ b/src/paperless/validators.py
@@ -17,6 +17,7 @@ ALLOWED_SVG_TAGS: set[str] = {
"text", # Text container
"tspan", # Text span within text
"textpath", # Text along a path
+ "style", # Embedded CSS
# Definitions and reusable content
"defs", # Container for reusable elements
"symbol", # Reusable graphic template
@@ -153,7 +154,9 @@ DANGEROUS_STYLE_PATTERNS: set[str] = {
"@import", # CSS @import directive
"-moz-binding:", # Firefox XBL bindings (can execute code)
"behaviour:", # IE behavior property
+ "behavior:", # IE behavior property (US spelling)
"vbscript:", # VBScript URLs
+ "data:application/", # Data URIs for arbitrary application payloads
}
XLINK_NS: set[str] = {
@@ -193,6 +196,15 @@ def reject_dangerous_svg(file: UploadedFile) -> None:
if tag not in ALLOWED_SVG_TAGS:
raise ValidationError(f"Disallowed SVG tag: <{tag}>")
+ if tag == "style":
+ # Combine all text (including CDATA) to scan for dangerous patterns
+ style_text: str = "".join(element.itertext()).lower()
+ for pattern in DANGEROUS_STYLE_PATTERNS:
+ if pattern in style_text:
+ raise ValidationError(
+ f"Disallowed pattern in