From 63dab0ab09448e84efed3c469d7a08f5b3b80c05 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Fri, 24 Oct 2025 16:25:59 -0700 Subject: [PATCH] Change: restrict superuser modifications to superusers only --- src/documents/tests/test_admin.py | 35 +++++++++++++++++++++++++++++++ src/paperless/views.py | 4 ++++ 2 files changed, 39 insertions(+) diff --git a/src/documents/tests/test_admin.py b/src/documents/tests/test_admin.py index 278014f7cd..61a579dc74 100644 --- a/src/documents/tests/test_admin.py +++ b/src/documents/tests/test_admin.py @@ -2,9 +2,11 @@ import types from unittest.mock import patch from django.contrib.admin.sites import AdminSite +from django.contrib.auth.models import Permission from django.contrib.auth.models import User from django.test import TestCase from django.utils import timezone +from rest_framework import status from documents import index from documents.admin import DocumentAdmin @@ -125,3 +127,36 @@ class TestPaperlessAdmin(DirectoriesMixin, TestCase): form.request = types.SimpleNamespace(user=superuser) self.assertTrue(form.is_valid()) self.assertEqual({}, form.errors) + + def test_superuser_can_only_be_modified_by_superuser(self): + superuser = User.objects.create_superuser(username="superuser", password="test") + user = User.objects.create( + username="test", + is_superuser=False, + is_staff=True, + ) + change_user_perm = Permission.objects.get(codename="change_user") + user.user_permissions.add(change_user_perm) + + self.client.force_login(user) + response = self.client.patch( + f"/api/users/{superuser.pk}/", + {"first_name": "Updated"}, + content_type="application/json", + ) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + self.assertEqual( + response.content.decode(), + "Superusers can only be modified by other superusers", + ) + + self.client.logout() + self.client.force_login(superuser) + response = self.client.patch( + f"/api/users/{superuser.pk}/", + {"first_name": "Updated"}, + content_type="application/json", + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + superuser.refresh_from_db() + self.assertEqual(superuser.first_name, "Updated") diff --git a/src/paperless/views.py b/src/paperless/views.py index fc5bb54634..69375e1bc2 100644 --- a/src/paperless/views.py +++ b/src/paperless/views.py @@ -125,6 +125,10 @@ class UserViewSet(ModelViewSet): def update(self, request, *args, **kwargs): user_to_update: User = self.get_object() + if not request.user.is_superuser and user_to_update.is_superuser: + return HttpResponseForbidden( + "Superusers can only be modified by other superusers", + ) if ( not request.user.is_superuser and request.data.get("is_superuser") is not None -- 2.47.3