From b1c406680f345f4aeec0989424dbcc839c75e438 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sat, 16 Aug 2025 07:34:00 -0700 Subject: [PATCH] Merge commit from fork * Security: prevent XSS with storage path template rendering * Security: prevent XSS svg uploads * Security: force attachment disposition for logo * Add suggestions from code review * Improve SVG validation with allowlist for tags and attributes --- .../management-list.component.html | 2 + .../management-list.component.ts | 2 + .../storage-path-list.component.ts | 4 +- src/documents/tests/samples/malicious.svg | 4 + src/documents/tests/test_api_app_config.py | 31 ++++++ src/documents/views.py | 27 +++++ src/paperless/serialisers.py | 7 ++ src/paperless/urls.py | 10 +- src/paperless/validators.py | 102 ++++++++++++++++++ 9 files changed, 179 insertions(+), 10 deletions(-) create mode 100644 src/documents/tests/samples/malicious.svg create mode 100644 src/paperless/validators.py diff --git a/src-ui/src/app/components/manage/management-list/management-list.component.html b/src-ui/src/app/components/manage/management-list/management-list.component.html index 6375a3667..7e8f46511 100644 --- a/src-ui/src/app/components/manage/management-list/management-list.component.html +++ b/src-ui/src/app/components/manage/management-list/management-list.component.html @@ -68,6 +68,8 @@
${c.path?.slice(0, 49)}${c.path?.length > 50 ? '...' : ''}
`
+ return `${c.path?.slice(0, 49)}${c.path?.length > 50 ? '...' : ''}`
},
},
]
diff --git a/src/documents/tests/samples/malicious.svg b/src/documents/tests/samples/malicious.svg
new file mode 100644
index 000000000..11fb65821
--- /dev/null
+++ b/src/documents/tests/samples/malicious.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/documents/tests/test_api_app_config.py b/src/documents/tests/test_api_app_config.py
index 5968b1670..b43d312b7 100644
--- a/src/documents/tests/test_api_app_config.py
+++ b/src/documents/tests/test_api_app_config.py
@@ -149,6 +149,11 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
THEN:
- old app_logo file is deleted
"""
+ admin = User.objects.create_superuser(username="admin")
+ self.client.force_login(user=admin)
+ response = self.client.get("/logo/")
+ self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
+
with (Path(__file__).parent / "samples" / "simple.jpg").open("rb") as f:
self.client.patch(
f"{self.ENDPOINT}1/",
@@ -156,6 +161,12 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
"app_logo": f,
},
)
+
+ # Logo exists at /logo/simple.jpg
+ response = self.client.get("/logo/simple.jpg")
+ self.assertEqual(response.status_code, status.HTTP_200_OK)
+ self.assertIn("image/jpeg", response["Content-Type"])
+
config = ApplicationConfiguration.objects.first()
old_logo = config.app_logo
self.assertTrue(Path(old_logo.path).exists())
@@ -168,6 +179,26 @@ class TestApiAppConfig(DirectoriesMixin, APITestCase):
)
self.assertFalse(Path(old_logo.path).exists())
+ def test_api_rejects_malicious_svg_logo(self):
+ """
+ GIVEN:
+ - An SVG logo containing a