티스토리 수익 글 보기

티스토리 수익 글 보기

[6.0.x] Fixed CVE-2026-4292 — Disallowed instance creation via Model… · django/django@428c48f · GitHub
Skip to content

Commit 428c48f

Browse files
[6.0.x] Fixed CVE-2026-4292 — Disallowed instance creation via ModelAdmin.list_editable.
Thanks Natalia Bidart, Jake Howard, and Markus Holtermann for reviews. Backport of 6afe7ce from main.
1 parent 08a752c commit 428c48f

6 files changed

Lines changed: 59 additions & 1 deletion

File tree

django/contrib/admin/options.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from django.contrib.admin.widgets import AutocompleteSelect, AutocompleteSelectMultiple
3333
from django.contrib.auth import get_permission_codename
3434
from django.core.exceptions import (
35+
BadRequest,
3536
FieldDoesNotExist,
3637
FieldError,
3738
PermissionDenied,
@@ -2072,6 +2073,8 @@ def changelist_view(self, request, extra_context=None):
20722073
for form in formset.forms:
20732074
if form.has_changed():
20742075
obj = self.save_form(request, form, change=True)
2076+
if obj._state.adding:
2077+
raise BadRequest("list_editable does not allow adding.")
20752078
self.save_model(request, obj, form, change=True)
20762079
self.save_related(request, form, formsets=[], change=True)
20772080
change_msg = self.construct_change_message(

docs/releases/4.2.30.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,13 @@ forged ``POST`` data in
3636

3737
This issue has severity "low" according to the :ref:`Django security policy
3838
<security-disclosure>`.
39+
40+
CVE-2026-4292: Privilege abuse in ``ModelAdmin.list_editable``
41+
==============================================================
42+
43+
Admin changelist forms using
44+
:attr:`~django.contrib.admin.ModelAdmin.list_editable` incorrectly allowed new
45+
instances to be created via forged ``POST`` data.
46+
47+
This issue has severity "low" according to the :ref:`Django security policy
48+
<security-disclosure>`.

docs/releases/5.2.13.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,13 @@ forged ``POST`` data in
3636

3737
This issue has severity "low" according to the :ref:`Django security policy
3838
<security-disclosure>`.
39+
40+
CVE-2026-4292: Privilege abuse in ``ModelAdmin.list_editable``
41+
==============================================================
42+
43+
Admin changelist forms using
44+
:attr:`~django.contrib.admin.ModelAdmin.list_editable` incorrectly allowed new
45+
instances to be created via forged ``POST`` data.
46+
47+
This issue has severity "low" according to the :ref:`Django security policy
48+
<security-disclosure>`.

docs/releases/6.0.4.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ forged ``POST`` data in
3737
This issue has severity "low" according to the :ref:`Django security policy
3838
<security-disclosure>`.
3939

40+
CVE-2026-4292: Privilege abuse in ``ModelAdmin.list_editable``
41+
==============================================================
42+
43+
Admin changelist forms using
44+
:attr:`~django.contrib.admin.ModelAdmin.list_editable` incorrectly allowed new
45+
instances to be created via forged ``POST`` data.
46+
47+
This issue has severity "low" according to the :ref:`Django security policy
48+
<security-disclosure>`.
49+
4050
Bugfixes
4151
========
4252

tests/admin_views/admin.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,14 @@ def get_queryset(self, request):
364364
return super().get_queryset(request).order_by("age")
365365

366366

367+
class ParentWithUUIDPKAdmin(admin.ModelAdmin):
368+
list_display = ("id", "title")
369+
list_editable = ("title",)
370+
371+
def has_add_permission(self, request):
372+
return False
373+
374+
367375
class FooAccountAdmin(admin.StackedInline):
368376
model = FooAccount
369377
extra = 1
@@ -1278,7 +1286,7 @@ class CourseAdmin(admin.ModelAdmin):
12781286
site.register(InlineReferer, InlineRefererAdmin)
12791287
site.register(ReferencedByGenRel)
12801288
site.register(GenRelReference)
1281-
site.register(ParentWithUUIDPK)
1289+
site.register(ParentWithUUIDPK, ParentWithUUIDPKAdmin)
12821290
site.register(RelatedPrepopulated, search_fields=["name"])
12831291
site.register(RelatedWithUUIDPKModel)
12841292
site.register(ReadOnlyRelatedField, ReadOnlyRelatedFieldAdmin)

tests/admin_views/tests.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import re
44
import unittest
55
import zoneinfo
6+
from http import HTTPStatus
67
from unittest import mock
78
from urllib.parse import parse_qsl, urljoin, urlsplit
89

@@ -4370,6 +4371,22 @@ def test_post_submission(self):
43704371

43714372
self.assertIs(Person.objects.get(name="John Mauchly").alive, False)
43724373

4374+
def test_forged_post_submission_when_no_add_permission(self):
4375+
before_count = ParentWithUUIDPK.objects.count()
4376+
data = {
4377+
"form-TOTAL_FORMS": "1",
4378+
"form-INITIAL_FORMS": "0",
4379+
"form-MAX_NUM_FORMS": "0",
4380+
"form-0-title": "The News",
4381+
"form-0-id": "",
4382+
"_save": "Save",
4383+
}
4384+
# This model admin allows no add permissions.
4385+
changelist_url = reverse("admin:admin_views_parentwithuuidpk_changelist")
4386+
response = self.client.post(changelist_url, data)
4387+
self.assertEqual(response.status_code, HTTPStatus.BAD_REQUEST)
4388+
self.assertEqual(ParentWithUUIDPK.objects.count(), before_count)
4389+
43734390
def test_non_field_errors(self):
43744391
"""
43754392
Non-field errors are displayed for each of the forms in the

0 commit comments

Comments
 (0)