diff options
| -rw-r--r-- | django/contrib/admin/widgets.py | 6 | ||||
| -rw-r--r-- | docs/releases/2.2.13.txt | 7 | ||||
| -rw-r--r-- | docs/releases/3.0.7.txt | 7 | ||||
| -rw-r--r-- | tests/admin_widgets/models.py | 8 | ||||
| -rw-r--r-- | tests/admin_widgets/tests.py | 11 |
5 files changed, 36 insertions, 3 deletions
diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index 7db57f4098..816f848ff0 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -12,7 +12,7 @@ from django.db.models.deletion import CASCADE from django.urls import reverse from django.urls.exceptions import NoReverseMatch from django.utils.html import smart_urlquote -from django.utils.safestring import mark_safe +from django.utils.http import urlencode from django.utils.text import Truncator from django.utils.translation import get_language, gettext as _ @@ -150,8 +150,8 @@ class ForeignKeyRawIdWidget(forms.TextInput): params = self.url_parameters() if params: - related_url += '?' + '&'.join('%s=%s' % (k, v) for k, v in params.items()) - context['related_url'] = mark_safe(related_url) + related_url += '?' + urlencode(params) + context['related_url'] = related_url context['link_title'] = _('Lookup') # The JavaScript code looks for this class. context['widget']['attrs'].setdefault('class', 'vForeignKeyRawIdAdminField') diff --git a/docs/releases/2.2.13.txt b/docs/releases/2.2.13.txt index 2e149a1f18..ee381fdcce 100644 --- a/docs/releases/2.2.13.txt +++ b/docs/releases/2.2.13.txt @@ -6,6 +6,13 @@ Django 2.2.13 release notes Django 2.2.13 fixes two security issues and a regression in 2.2.12. +CVE-2020-13596: Possible XSS via admin ``ForeignKeyRawIdWidget`` +================================================================ + +Query parameters for the admin ``ForeignKeyRawIdWidget`` were not properly URL +encoded, posing an XSS attack vector. ``ForeignKeyRawIdWidget`` now +ensures query parameters are correctly URL encoded. + Bugfixes ======== diff --git a/docs/releases/3.0.7.txt b/docs/releases/3.0.7.txt index f1775b3471..51ac0d7edd 100644 --- a/docs/releases/3.0.7.txt +++ b/docs/releases/3.0.7.txt @@ -6,6 +6,13 @@ Django 3.0.7 release notes Django 3.0.7 fixes two security issues and several bugs in 3.0.6. +CVE-2020-13596: Possible XSS via admin ``ForeignKeyRawIdWidget`` +================================================================ + +Query parameters for the admin ``ForeignKeyRawIdWidget`` were not properly URL +encoded, posing an XSS attack vector. ``ForeignKeyRawIdWidget`` now +ensures query parameters are correctly URL encoded. + Bugfixes ======== diff --git a/tests/admin_widgets/models.py b/tests/admin_widgets/models.py index b5025fdfd7..88bf2b8fca 100644 --- a/tests/admin_widgets/models.py +++ b/tests/admin_widgets/models.py @@ -27,6 +27,14 @@ class Band(models.Model): return self.name +class UnsafeLimitChoicesTo(models.Model): + band = models.ForeignKey( + Band, + models.CASCADE, + limit_choices_to={'name': '"&><escapeme'}, + ) + + class Album(models.Model): band = models.ForeignKey(Band, models.CASCADE) featuring = models.ManyToManyField(Band, related_name='featured') diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py index 7aa597a87d..7d3d71181e 100644 --- a/tests/admin_widgets/tests.py +++ b/tests/admin_widgets/tests.py @@ -22,6 +22,7 @@ from django.utils import translation from .models import ( Advisor, Album, Band, Bee, Car, Company, Event, Honeycomb, Individual, Inventory, Member, MyFileField, Profile, School, Student, + UnsafeLimitChoicesTo, ) from .widgetadmin import site as widget_admin_site @@ -586,6 +587,16 @@ class ForeignKeyRawIdWidgetTest(TestCase): 'Hidden</a></strong>' % {'pk': hidden.pk} ) + def test_render_unsafe_limit_choices_to(self): + rel = UnsafeLimitChoicesTo._meta.get_field('band').remote_field + w = widgets.ForeignKeyRawIdWidget(rel, widget_admin_site) + self.assertHTMLEqual( + w.render('test', None), + '<input type="text" name="test" class="vForeignKeyRawIdAdminField">\n' + '<a href="/admin_widgets/band/?name=%22%26%3E%3Cescapeme&_to_field=id" ' + 'class="related-lookup" id="lookup_id_test" title="Lookup"></a>' + ) + @override_settings(ROOT_URLCONF='admin_widgets.urls') class ManyToManyRawIdWidgetTest(TestCase): |
