From 8a5eadd140a5f06d24e1c5bc0c444ce11be0769a Mon Sep 17 00:00:00 2001 From: Luke Plant Date: Tue, 21 Jul 2015 13:35:11 +0100 Subject: [PATCH] Corrected HTML-escaping behaviour of url template tag. Due to the URL encoding applied by the tag for all parameters that might be partly controllable by an end-user, there are no XSS/security problems caused by this bug, only invalid HTML. --- django/template/defaulttags.py | 4 +++- tests/template_tests/syntax_tests/test_url.py | 11 ++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/django/template/defaulttags.py b/django/template/defaulttags.py index b0501505b5..90bdbc25d0 100644 --- a/django/template/defaulttags.py +++ b/django/template/defaulttags.py @@ -12,7 +12,7 @@ from django.conf import settings from django.utils import six, timezone from django.utils.deprecation import RemovedInDjango110Warning from django.utils.encoding import force_text, smart_text -from django.utils.html import format_html +from django.utils.html import conditional_escape, format_html from django.utils.lorem_ipsum import paragraphs, words from django.utils.safestring import mark_safe @@ -512,6 +512,8 @@ class URLNode(Node): context[self.asvar] = url return '' else: + if context.autoescape: + url = conditional_escape(url) return url diff --git a/tests/template_tests/syntax_tests/test_url.py b/tests/template_tests/syntax_tests/test_url.py index d593591480..91ed8affb7 100644 --- a/tests/template_tests/syntax_tests/test_url.py +++ b/tests/template_tests/syntax_tests/test_url.py @@ -95,7 +95,7 @@ class UrlTagTests(SimpleTestCase): @ignore_warnings(category=RemovedInDjango110Warning) def test_url12(self): output = self.engine.render_to_string('url12', {'client': {'id': 1}}) - self.assertEqual(output, '/client/1/!$&\'()*+,;=~:@,/') + self.assertEqual(output, '/client/1/!$&'()*+,;=~:@,/') @ignore_warnings(category=RemovedInDjango110Warning) @setup({'url13': '{% url "template_tests.views.client_action" ' @@ -133,6 +133,15 @@ class UrlTagTests(SimpleTestCase): output = self.engine.render_to_string('url20', {'client': {'id': 1}, 'url_name_in_var': 'named.client'}) self.assertEqual(output, '/named-client/1/') + @setup({'url21': '{% autoescape off %}' + '{% url "template_tests.views.client_action" ' + 'id=client.id action="!$&\'()*+,;=~:@," %}' + '{% endautoescape %}'}) + @ignore_warnings(category=RemovedInDjango110Warning) + def test_url21(self): + output = self.engine.render_to_string('url21', {'client': {'id': 1}}) + self.assertEqual(output, '/client/1/!$&\'()*+,;=~:@,/') + # Failures @setup({'url-fail01': '{% url %}'}) def test_url_fail01(self):