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