diff options
| author | Jacob Walls <jacobtylerwalls@gmail.com> | 2026-03-12 11:00:05 -0400 |
|---|---|---|
| committer | Jacob Walls <jacobtylerwalls@gmail.com> | 2026-04-07 07:12:16 -0400 |
| commit | ef8b25dcc06d158683a5623ce406d561638f4073 (patch) | |
| tree | cd2cdb9556e001c770247091a49b14b2850a3a59 /django | |
| parent | caf90a971f09323775ed0cacf94eadaf39d040e0 (diff) | |
Fixed CVE-2026-4277 -- Checked add permissions in GenericInlineModelAdmin.
Edit permissions were still checked as part of ordinary form validation,
but because GenericInlineModelAdmin overrides get_formset(), it lacked
InlineModelAdmin's dynamic DeleteProtectedModelForm.has_changed() logic
for checking permissions server-side, leaving the add case unaddressed.
This change reimplements the relevant part of InlineModelAdmin.get_formset().
Thanks N05ec@LZU-DSLab for the report, and Natalia Bidart,
Markus Holtermann, and Simon Charette for reviews.
Diffstat (limited to 'django')
| -rw-r--r-- | django/contrib/contenttypes/admin.py | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/django/contrib/contenttypes/admin.py b/django/contrib/contenttypes/admin.py index f595ce5285..d324a4f4fe 100644 --- a/django/contrib/contenttypes/admin.py +++ b/django/contrib/contenttypes/admin.py @@ -127,6 +127,21 @@ class GenericInlineModelAdmin(InlineModelAdmin): **kwargs, } + base_model_form = defaults["form"] + can_change = self.has_change_permission(request, obj) if request else True + can_add = self.has_add_permission(request, obj) if request else True + + class PermissionProtectedModelForm(base_model_form): + def has_changed(self): + # Protect against unauthorized edits. + if not can_change and not self.instance._state.adding: + return False + if not can_add and self.instance._state.adding: + return False + return super().has_changed() + + defaults["form"] = PermissionProtectedModelForm + if defaults["fields"] is None and not modelform_defines_fields( defaults["form"] ): |
