diff options
| -rw-r--r-- | django/contrib/admin/options.py | 3 | ||||
| -rw-r--r-- | docs/releases/4.2.30.txt | 10 | ||||
| -rw-r--r-- | docs/releases/5.2.13.txt | 10 | ||||
| -rw-r--r-- | docs/releases/6.0.4.txt | 10 | ||||
| -rw-r--r-- | tests/admin_views/admin.py | 10 | ||||
| -rw-r--r-- | tests/admin_views/tests.py | 17 |
6 files changed, 59 insertions, 1 deletions
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 6c202c8e61..0d9b62faea 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -32,6 +32,7 @@ from django.contrib.admin.utils import ( from django.contrib.admin.widgets import AutocompleteSelect, AutocompleteSelectMultiple from django.contrib.auth import get_permission_codename from django.core.exceptions import ( + BadRequest, FieldDoesNotExist, FieldError, PermissionDenied, @@ -2072,6 +2073,8 @@ class ModelAdmin(BaseModelAdmin): for form in formset.forms: if form.has_changed(): obj = self.save_form(request, form, change=True) + if obj._state.adding: + raise BadRequest("list_editable does not allow adding.") self.save_model(request, obj, form, change=True) self.save_related(request, form, formsets=[], change=True) change_msg = self.construct_change_message( diff --git a/docs/releases/4.2.30.txt b/docs/releases/4.2.30.txt index a6d2deef3c..de19a6f08f 100644 --- a/docs/releases/4.2.30.txt +++ b/docs/releases/4.2.30.txt @@ -36,3 +36,13 @@ forged ``POST`` data in This issue has severity "low" according to the :ref:`Django security policy <security-disclosure>`. + +CVE-2026-4292: Privilege abuse in ``ModelAdmin.list_editable`` +============================================================== + +Admin changelist forms using +:attr:`~django.contrib.admin.ModelAdmin.list_editable` incorrectly allowed new +instances to be created via forged ``POST`` data. + +This issue has severity "low" according to the :ref:`Django security policy +<security-disclosure>`. diff --git a/docs/releases/5.2.13.txt b/docs/releases/5.2.13.txt index 8b03103508..8b303f2700 100644 --- a/docs/releases/5.2.13.txt +++ b/docs/releases/5.2.13.txt @@ -36,3 +36,13 @@ forged ``POST`` data in This issue has severity "low" according to the :ref:`Django security policy <security-disclosure>`. + +CVE-2026-4292: Privilege abuse in ``ModelAdmin.list_editable`` +============================================================== + +Admin changelist forms using +:attr:`~django.contrib.admin.ModelAdmin.list_editable` incorrectly allowed new +instances to be created via forged ``POST`` data. + +This issue has severity "low" according to the :ref:`Django security policy +<security-disclosure>`. diff --git a/docs/releases/6.0.4.txt b/docs/releases/6.0.4.txt index 73b08436c1..4287a3086a 100644 --- a/docs/releases/6.0.4.txt +++ b/docs/releases/6.0.4.txt @@ -37,6 +37,16 @@ forged ``POST`` data in This issue has severity "low" according to the :ref:`Django security policy <security-disclosure>`. +CVE-2026-4292: Privilege abuse in ``ModelAdmin.list_editable`` +============================================================== + +Admin changelist forms using +:attr:`~django.contrib.admin.ModelAdmin.list_editable` incorrectly allowed new +instances to be created via forged ``POST`` data. + +This issue has severity "low" according to the :ref:`Django security policy +<security-disclosure>`. + Bugfixes ======== diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py index 499bba401a..f489c3e6f5 100644 --- a/tests/admin_views/admin.py +++ b/tests/admin_views/admin.py @@ -364,6 +364,14 @@ class PersonAdmin(admin.ModelAdmin): return super().get_queryset(request).order_by("age") +class ParentWithUUIDPKAdmin(admin.ModelAdmin): + list_display = ("id", "title") + list_editable = ("title",) + + def has_add_permission(self, request): + return False + + class FooAccountAdmin(admin.StackedInline): model = FooAccount extra = 1 @@ -1278,7 +1286,7 @@ site.register(ReferencedByInline) site.register(InlineReferer, InlineRefererAdmin) site.register(ReferencedByGenRel) site.register(GenRelReference) -site.register(ParentWithUUIDPK) +site.register(ParentWithUUIDPK, ParentWithUUIDPKAdmin) site.register(RelatedPrepopulated, search_fields=["name"]) site.register(RelatedWithUUIDPKModel) site.register(ReadOnlyRelatedField, ReadOnlyRelatedFieldAdmin) diff --git a/tests/admin_views/tests.py b/tests/admin_views/tests.py index f766794c54..db19f75aa9 100644 --- a/tests/admin_views/tests.py +++ b/tests/admin_views/tests.py @@ -3,6 +3,7 @@ import os import re import unittest import zoneinfo +from http import HTTPStatus from unittest import mock from urllib.parse import parse_qsl, urljoin, urlsplit @@ -4370,6 +4371,22 @@ class AdminViewListEditable(TestCase): self.assertIs(Person.objects.get(name="John Mauchly").alive, False) + def test_forged_post_submission_when_no_add_permission(self): + before_count = ParentWithUUIDPK.objects.count() + data = { + "form-TOTAL_FORMS": "1", + "form-INITIAL_FORMS": "0", + "form-MAX_NUM_FORMS": "0", + "form-0-title": "The News", + "form-0-id": "", + "_save": "Save", + } + # This model admin allows no add permissions. + changelist_url = reverse("admin:admin_views_parentwithuuidpk_changelist") + response = self.client.post(changelist_url, data) + self.assertEqual(response.status_code, HTTPStatus.BAD_REQUEST) + self.assertEqual(ParentWithUUIDPK.objects.count(), before_count) + def test_non_field_errors(self): """ Non-field errors are displayed for each of the forms in the |
