Skip to content

Commit 58e08e8

Browse files
committed
[1.10.x] Fixed CVE-2017-12794 -- Fixed XSS possibility in traceback section of technical 500 debug page.
This is a security fix.
1 parent fba3c96 commit 58e08e8

File tree

3 files changed

+25
-17
lines changed

3 files changed

+25
-17
lines changed

django/views/debug.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -775,38 +775,37 @@ def default_urlconf(request):
775775
<h2>Traceback <span class="commands">{% if not is_email %}<a href="#" onclick="return switchPastebinFriendly(this);">
776776
Switch to copy-and-paste view</a></span>{% endif %}
777777
</h2>
778-
{% autoescape off %}
779778
<div id="browserTraceback">
780779
<ul class="traceback">
781780
{% for frame in frames %}
782781
{% ifchanged frame.exc_cause %}{% if frame.exc_cause %}
783782
<li><h3>
784783
{% if frame.exc_cause_explicit %}
785-
The above exception ({{ frame.exc_cause }}) was the direct cause of the following exception:
784+
The above exception ({{ frame.exc_cause|force_escape }}) was the direct cause of the following exception:
786785
{% else %}
787-
During handling of the above exception ({{ frame.exc_cause }}), another exception occurred:
786+
During handling of the above exception ({{ frame.exc_cause|force_escape }}), another exception occurred:
788787
{% endif %}
789788
</h3></li>
790789
{% endif %}{% endifchanged %}
791790
<li class="frame {{ frame.type }}">
792-
<code>{{ frame.filename|escape }}</code> in <code>{{ frame.function|escape }}</code>
791+
<code>{{ frame.filename }}</code> in <code>{{ frame.function }}</code>
793792
794793
{% if frame.context_line %}
795794
<div class="context" id="c{{ frame.id }}">
796795
{% if frame.pre_context and not is_email %}
797796
<ol start="{{ frame.pre_context_lineno }}" class="pre-context" id="pre{{ frame.id }}">
798797
{% for line in frame.pre_context %}
799-
<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')"><pre>{{ line|escape }}</pre></li>
798+
<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')"><pre>{{ line }}</pre></li>
800799
{% endfor %}
801800
</ol>
802801
{% endif %}
803802
<ol start="{{ frame.lineno }}" class="context-line">
804803
<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')"><pre>
805-
""" """{{ frame.context_line|escape }}</pre>{% if not is_email %} <span>...</span>{% endif %}</li></ol>
804+
""" """{{ frame.context_line }}</pre>{% if not is_email %} <span>...</span>{% endif %}</li></ol>
806805
{% if frame.post_context and not is_email %}
807806
<ol start='{{ frame.lineno|add:"1" }}' class="post-context" id="post{{ frame.id }}">
808807
{% for line in frame.post_context %}
809-
<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')"><pre>{{ line|escape }}</pre></li>
808+
<li onclick="toggle('pre{{ frame.id }}', 'post{{ frame.id }}')"><pre>{{ line }}</pre></li>
810809
{% endfor %}
811810
</ol>
812811
{% endif %}
@@ -831,7 +830,7 @@ def default_urlconf(request):
831830
<tbody>
832831
{% for var in frame.vars|dictsort:0 %}
833832
<tr>
834-
<td>{{ var.0|force_escape }}</td>
833+
<td>{{ var.0 }}</td>
835834
<td class="code"><pre>{{ var.1 }}</pre></td>
836835
</tr>
837836
{% endfor %}
@@ -842,7 +841,6 @@ def default_urlconf(request):
842841
{% endfor %}
843842
</ul>
844843
</div>
845-
{% endautoescape %}
846844
<form action="http://dpaste.com/" name="pasteform" id="pasteform" method="post">
847845
{% if not is_email %}
848846
<div id="pastebinTraceback" class="pastebin">
@@ -888,9 +886,9 @@ def default_urlconf(request):
888886
889887
Traceback:{% for frame in frames %}
890888
{% ifchanged frame.exc_cause %}{% if frame.exc_cause %}{% if frame.exc_cause_explicit %}
891-
The above exception ({{ frame.exc_cause }}) was the direct cause of the following exception:
889+
The above exception ({{ frame.exc_cause|force_escape }}) was the direct cause of the following exception:
892890
{% else %}
893-
During handling of the above exception ({{ frame.exc_cause }}), another exception occurred:
891+
During handling of the above exception ({{ frame.exc_cause|force_escape }}), another exception occurred:
894892
{% endif %}{% endif %}{% endifchanged %}
895893
File "{{ frame.filename|escape }}" in {{ frame.function|escape }}
896894
{% if frame.context_line %} {{ frame.lineno }}. {{ frame.context_line|escape }}{% endif %}{% endfor %}

docs/releases/1.10.8.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,12 @@ Django 1.10.8 release notes
55
*September 5, 2017*
66

77
Django 1.10.8 fixes a security issue in 1.10.7.
8+
9+
CVE-2017-12794: Possible XSS in traceback section of technical 500 debug page
10+
=============================================================================
11+
12+
In older versions, HTML autoescaping was disabled in a portion of the template
13+
for the technical 500 debug page. Given the right circumstances, this allowed
14+
a cross-site scripting attack. This vulnerability shouldn't affect most
15+
production sites since you shouldn't run with ``DEBUG = True`` (which makes
16+
this page accessible) in your production settings.

tests/view_tests/tests/py3_test_debug.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import sys
1010

1111
from django.test import RequestFactory, TestCase
12+
from django.utils.safestring import mark_safe
1213
from django.views.debug import ExceptionReporter
1314

1415

@@ -20,10 +21,10 @@ def test_reporting_of_nested_exceptions(self):
2021
request = self.rf.get('/test_view/')
2122
try:
2223
try:
23-
raise AttributeError('Top level')
24+
raise AttributeError(mark_safe('<p>Top level</p>'))
2425
except AttributeError as explicit:
2526
try:
26-
raise ValueError('Second exception') from explicit
27+
raise ValueError('<p>Second exception</p>') from explicit
2728
except ValueError:
2829
raise IndexError('Final exception')
2930
except Exception:
@@ -37,9 +38,9 @@ def test_reporting_of_nested_exceptions(self):
3738
html = reporter.get_traceback_html()
3839
# Both messages are twice on page -- one rendered as html,
3940
# one as plain text (for pastebin)
40-
self.assertEqual(2, html.count(explicit_exc.format("Top level")))
41-
self.assertEqual(2, html.count(implicit_exc.format("Second exception")))
41+
self.assertEqual(2, html.count(explicit_exc.format('&lt;p&gt;Top level&lt;/p&gt;')))
42+
self.assertEqual(2, html.count(implicit_exc.format('&lt;p&gt;Second exception&lt;/p&gt;')))
4243

4344
text = reporter.get_traceback_text()
44-
self.assertIn(explicit_exc.format("Top level"), text)
45-
self.assertIn(implicit_exc.format("Second exception"), text)
45+
self.assertIn(explicit_exc.format('<p>Top level</p>'), text)
46+
self.assertIn(implicit_exc.format('<p>Second exception</p>'), text)

0 commit comments

Comments
 (0)