+68
-11
lines changedFilter options
+68
-11
lines changed Original file line number Diff line number Diff line change
@@ -1 +1 @@
1
-
{% if widget.value %}<p class="url">{{ current_label }} <a href="{{ widget.href }}">{{ widget.value }}</a><br>{{ change_label }} {% endif %}{% include "django/forms/widgets/input.html" %}{% if widget.value %}</p>{% endif %}
1
+
{% if url_valid %}<p class="url">{{ current_label }} <a href="{{ widget.href }}">{{ widget.value }}</a><br>{{ change_label }} {% endif %}{% include "django/forms/widgets/input.html" %}{% if url_valid %}</p>{% endif %}
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
7
7
from django import forms
8
8
from django.conf import settings
9
9
from django.core.exceptions import ValidationError
10
+
from django.core.validators import URLValidator
10
11
from django.db.models.deletion import CASCADE
11
12
from django.urls import reverse
12
13
from django.urls.exceptions import NoReverseMatch
@@ -330,14 +331,21 @@ def __init__(self, attrs=None):
330
331
class AdminURLFieldWidget(forms.URLInput):
331
332
template_name = 'admin/widgets/url.html'
332
333
333
-
def __init__(self, attrs=None):
334
+
def __init__(self, attrs=None, validator_class=URLValidator):
334
335
super().__init__(attrs={'class': 'vURLField', **(attrs or {})})
336
+
self.validator = validator_class()
335
337
336
338
def get_context(self, name, value, attrs):
339
+
try:
340
+
self.validator(value if value else '')
341
+
url_valid = True
342
+
except ValidationError:
343
+
url_valid = False
337
344
context = super().get_context(name, value, attrs)
338
345
context['current_label'] = _('Currently:')
339
346
context['change_label'] = _('Change:')
340
347
context['widget']['href'] = smart_urlquote(context['widget']['value']) if value else ''
348
+
context['url_valid'] = url_valid
341
349
return context
342
350
343
351
Original file line number Diff line number Diff line change
@@ -4,4 +4,18 @@ Django 1.11.21 release notes
4
4
5
5
*June 3, 2019*
6
6
7
-
Django 1.11.21 fixes security issues in 1.11.20.
7
+
Django 1.11.21 fixes a security issue in 1.11.20.
8
+
9
+
CVE-2019-12308: AdminURLFieldWidget XSS
10
+
---------------------------------------
11
+
12
+
The clickable "Current URL" link generated by ``AdminURLFieldWidget`` displayed
13
+
the provided value without validating it as a safe URL. Thus, an unvalidated
14
+
value stored in the database, or a value provided as a URL query parameter
15
+
payload, could result in an clickable JavaScript link.
16
+
17
+
``AdminURLFieldWidget`` now validates the provided value using
18
+
:class:`~django.core.validators.URLValidator` before displaying the clickable
19
+
link. You may customise the validator by passing a ``validator_class`` kwarg to
20
+
``AdminURLFieldWidget.__init__()``, e.g. when using
21
+
:attr:`~django.contrib.admin.ModelAdmin.formfield_overrides`.
Original file line number Diff line number Diff line change
@@ -5,3 +5,17 @@ Django 2.1.9 release notes
5
5
*June 3, 2019*
6
6
7
7
Django 2.1.9 fixes security issues in 2.1.8.
8
+
9
+
CVE-2019-12308: AdminURLFieldWidget XSS
10
+
---------------------------------------
11
+
12
+
The clickable "Current URL" link generated by ``AdminURLFieldWidget`` displayed
13
+
the provided value without validating it as a safe URL. Thus, an unvalidated
14
+
value stored in the database, or a value provided as a URL query parameter
15
+
payload, could result in an clickable JavaScript link.
16
+
17
+
``AdminURLFieldWidget`` now validates the provided value using
18
+
:class:`~django.core.validators.URLValidator` before displaying the clickable
19
+
link. You may customise the validator by passing a ``validator_class`` kwarg to
20
+
``AdminURLFieldWidget.__init__()``, e.g. when using
21
+
:attr:`~django.contrib.admin.ModelAdmin.formfield_overrides`.
Original file line number Diff line number Diff line change
@@ -6,6 +6,20 @@ Django 2.2.2 release notes
6
6
7
7
Django 2.2.2 fixes security issues and several bugs in 2.2.1.
8
8
9
+
CVE-2019-12308: AdminURLFieldWidget XSS
10
+
---------------------------------------
11
+
12
+
The clickable "Current URL" link generated by ``AdminURLFieldWidget`` displayed
13
+
the provided value without validating it as a safe URL. Thus, an unvalidated
14
+
value stored in the database, or a value provided as a URL query parameter
15
+
payload, could result in an clickable JavaScript link.
16
+
17
+
``AdminURLFieldWidget`` now validates the provided value using
18
+
:class:`~django.core.validators.URLValidator` before displaying the clickable
19
+
link. You may customise the validator by passing a ``validator_class`` kwarg to
20
+
``AdminURLFieldWidget.__init__()``, e.g. when using
21
+
:attr:`~django.contrib.admin.ModelAdmin.formfield_overrides`.
22
+
9
23
Bugfixes
10
24
========
11
25
Original file line number Diff line number Diff line change
@@ -333,6 +333,13 @@ def test_localization(self):
333
333
334
334
335
335
class AdminURLWidgetTest(SimpleTestCase):
336
+
def test_get_context_validates_url(self):
337
+
w = widgets.AdminURLFieldWidget()
338
+
for invalid in ['', '/not/a/full/url/', 'javascript:alert("Danger XSS!")']:
339
+
with self.subTest(url=invalid):
340
+
self.assertFalse(w.get_context('name', invalid, {})['url_valid'])
341
+
self.assertTrue(w.get_context('name', 'http://example.com', {})['url_valid'])
342
+
336
343
def test_render(self):
337
344
w = widgets.AdminURLFieldWidget()
338
345
self.assertHTMLEqual(
@@ -366,31 +373,31 @@ def test_render_quoting(self):
366
373
VALUE_RE = re.compile('value="([^"]+)"')
367
374
TEXT_RE = re.compile('<a[^>]+>([^>]+)</a>')
368
375
w = widgets.AdminURLFieldWidget()
369
-
output = w.render('test', 'http://example.com/<sometag>some text</sometag>')
376
+
output = w.render('test', 'http://example.com/<sometag>some-text</sometag>')
370
377
self.assertEqual(
371
378
HREF_RE.search(output).groups()[0],
372
-
'http://example.com/%3Csometag%3Esome%20text%3C/sometag%3E',
379
+
'http://example.com/%3Csometag%3Esome-text%3C/sometag%3E',
373
380
)
374
381
self.assertEqual(
375
382
TEXT_RE.search(output).groups()[0],
376
-
'http://example.com/<sometag>some text</sometag>',
383
+
'http://example.com/<sometag>some-text</sometag>',
377
384
)
378
385
self.assertEqual(
379
386
VALUE_RE.search(output).groups()[0],
380
-
'http://example.com/<sometag>some text</sometag>',
387
+
'http://example.com/<sometag>some-text</sometag>',
381
388
)
382
-
output = w.render('test', 'http://example-äüö.com/<sometag>some text</sometag>')
389
+
output = w.render('test', 'http://example-äüö.com/<sometag>some-text</sometag>')
383
390
self.assertEqual(
384
391
HREF_RE.search(output).groups()[0],
385
-
'http://xn--example--7za4pnc.com/%3Csometag%3Esome%20text%3C/sometag%3E',
392
+
'http://xn--example--7za4pnc.com/%3Csometag%3Esome-text%3C/sometag%3E',
386
393
)
387
394
self.assertEqual(
388
395
TEXT_RE.search(output).groups()[0],
389
-
'http://example-äüö.com/<sometag>some text</sometag>',
396
+
'http://example-äüö.com/<sometag>some-text</sometag>',
390
397
)
391
398
self.assertEqual(
392
399
VALUE_RE.search(output).groups()[0],
393
-
'http://example-äüö.com/<sometag>some text</sometag>',
400
+
'http://example-äüö.com/<sometag>some-text</sometag>',
394
401
)
395
402
output = w.render('test', 'http://www.example.com/%C3%A4"><script>alert("XSS!")</script>"')
396
403
self.assertEqual(
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4