Index: Django-1.8.19/tests/handlers/tests.py =================================================================== --- Django-1.8.19/tests/handlers/tests.py +++ Django-1.8.19/tests/handlers/tests.py 2019-01-06 21:02:04.802549310 +0100 @@ -2,6 +2,8 @@ from __future__ import unicode_literals +import sys + from django.core.handlers.wsgi import WSGIHandler, WSGIRequest from django.core.signals import request_finished, request_started from django.db import close_old_connections, connection @@ -11,6 +13,7 @@ from django.utils import six from django.utils.encoding import force_str +PY37 = sys.version_info >= (3, 7, 0) class HandlerTests(TestCase): @@ -183,19 +186,19 @@ def test_invalid_urls(self): response = self.client.get('~%A9helloworld') self.assertEqual(response.status_code, 404) - self.assertContains(response, '~%A9helloworld', status_code=404) + self.assertEqual(response.context['request_path'], '/~%25A9helloworld' if PY37 else '/%7E%25A9helloworld') response = self.client.get('d%aao%aaw%aan%aal%aao%aaa%aad%aa/') self.assertEqual(response.status_code, 404) - self.assertContains(response, 'd%AAo%AAw%AAn%AAl%AAo%AAa%AAd%AA', status_code=404) + self.assertEqual(response.context['request_path'], '/d%25AAo%25AAw%25AAn%25AAl%25AAo%25AAa%25AAd%25AA') response = self.client.get('/%E2%99%E2%99%A5/') self.assertEqual(response.status_code, 404) - self.assertContains(response, '%E2%99\u2665', status_code=404) + self.assertEqual(response.context['request_path'], '/%25E2%2599%E2%99%A5/') response = self.client.get('/%E2%98%8E%E2%A9%E2%99%A5/') self.assertEqual(response.status_code, 404) - self.assertContains(response, '\u260e%E2%A9\u2665', status_code=404) + self.assertEqual(response.context['request_path'], '/%E2%98%8E%25E2%25A9%E2%99%A5/') def test_environ_path_info_type(self): environ = RequestFactory().get('/%E2%A8%87%87%A5%E2%A8%A0').environ Index: Django-1.8.19/django/views/defaults.py =================================================================== --- Django-1.8.19/django/views/defaults.py +++ Django-1.8.19/django/views/defaults.py 2019-01-06 20:56:06.531711830 +0100 @@ -1,5 +1,6 @@ from django import http from django.template import Context, Engine, TemplateDoesNotExist, loader +from django.utils.http import urlquote from django.views.decorators.csrf import requires_csrf_token @@ -14,9 +15,10 @@ Templates: :template:`404.html` Context: request_path - The path of the requested URL (e.g., '/app/pages/bad_page/') + The path of the requested URL (e.g., '/app/pages/bad_page/'). It's + quoted to prevent a content injection attack. """ - context = {'request_path': request.path} + context = {'request_path': urlquote(request.path)} try: template = loader.get_template(template_name) body = template.render(context, request) @@ -24,7 +26,7 @@ except TemplateDoesNotExist: template = Engine().from_string( '<h1>Not Found</h1>' - '<p>The requested URL {{ request_path }} was not found on this server.</p>') + '<p>The requested resource was not found on this server.</p>') body = template.render(Context(context)) content_type = 'text/html' return http.HttpResponseNotFound(body, content_type=content_type)