@@ -888,9 +886,9 @@ In template {{ template_info.name }}, error at line {{ template_info.line }}
Traceback:{% for frame in frames %}
{% ifchanged frame.exc_cause %}{% if frame.exc_cause %}{% if frame.exc_cause_explicit %}
-The above exception ({{ frame.exc_cause }}) was the direct cause of the following exception:
+The above exception ({{ frame.exc_cause|force_escape }}) was the direct cause of the following exception:
{% else %}
-During handling of the above exception ({{ frame.exc_cause }}), another exception occurred:
+During handling of the above exception ({{ frame.exc_cause|force_escape }}), another exception occurred:
{% endif %}{% endif %}{% endifchanged %}
File "{{ frame.filename|escape }}" in {{ frame.function|escape }}
{% if frame.context_line %} {{ frame.lineno }}. {{ frame.context_line|escape }}{% endif %}{% endfor %}
diff --git a/docs/releases/1.10.8.txt b/docs/releases/1.10.8.txt
index 160e555fef..3785e6535a 100644
--- a/docs/releases/1.10.8.txt
+++ b/docs/releases/1.10.8.txt
@@ -5,3 +5,12 @@ Django 1.10.8 release notes
*September 5, 2017*
Django 1.10.8 fixes a security issue in 1.10.7.
+
+CVE-2017-12794: Possible XSS in traceback section of technical 500 debug page
+=============================================================================
+
+In older versions, HTML autoescaping was disabled in a portion of the template
+for the technical 500 debug page. Given the right circumstances, this allowed
+a cross-site scripting attack. This vulnerability shouldn't affect most
+production sites since you shouldn't run with ``DEBUG = True`` (which makes
+this page accessible) in your production settings.
diff --git a/tests/view_tests/tests/py3_test_debug.py b/tests/view_tests/tests/py3_test_debug.py
index 30201bae53..316179ae3e 100644
--- a/tests/view_tests/tests/py3_test_debug.py
+++ b/tests/view_tests/tests/py3_test_debug.py
@@ -9,6 +9,7 @@ error (raise ... from ...) can't be silenced using NOQA.
import sys
from django.test import RequestFactory, TestCase
+from django.utils.safestring import mark_safe
from django.views.debug import ExceptionReporter
@@ -20,10 +21,10 @@ class Py3ExceptionReporterTests(TestCase):
request = self.rf.get('/test_view/')
try:
try:
- raise AttributeError('Top level')
+ raise AttributeError(mark_safe('
Top level
'))
except AttributeError as explicit:
try:
- raise ValueError('Second exception') from explicit
+ raise ValueError('
Second exception
') from explicit
except ValueError:
raise IndexError('Final exception')
except Exception:
@@ -37,9 +38,9 @@ class Py3ExceptionReporterTests(TestCase):
html = reporter.get_traceback_html()
# Both messages are twice on page -- one rendered as html,
# one as plain text (for pastebin)
- self.assertEqual(2, html.count(explicit_exc.format("Top level")))
- self.assertEqual(2, html.count(implicit_exc.format("Second exception")))
+ self.assertEqual(2, html.count(explicit_exc.format('<p>Top level</p>')))
+ self.assertEqual(2, html.count(implicit_exc.format('<p>Second exception</p>')))
text = reporter.get_traceback_text()
- self.assertIn(explicit_exc.format("Top level"), text)
- self.assertIn(implicit_exc.format("Second exception"), text)
+ self.assertIn(explicit_exc.format('
Top level
'), text)
+ self.assertIn(implicit_exc.format('
Second exception
'), text)