Fixed CVE-2019-14232 -- Adjusted regex to avoid backtracking issues when truncating HTML.
Thanks to Guido Vranken for initial report.
This commit is contained in:
parent
eea0bf7bd5
commit
7f65974f82
|
@ -17,8 +17,8 @@ def capfirst(x):
|
||||||
|
|
||||||
|
|
||||||
# Set up regular expressions
|
# Set up regular expressions
|
||||||
re_words = re.compile(r'<.*?>|((?:\w[-\w]*|&.*?;)+)', re.S)
|
re_words = re.compile(r'<[^>]+?>|([^<>\s]+)', re.S)
|
||||||
re_chars = re.compile(r'<.*?>|(.)', re.S)
|
re_chars = re.compile(r'<[^>]+?>|(.)', re.S)
|
||||||
re_tag = re.compile(r'<(/)?(\S+?)(?:(\s*/)|\s.*?)?>', re.S)
|
re_tag = re.compile(r'<(/)?(\S+?)(?:(\s*/)|\s.*?)?>', re.S)
|
||||||
re_newlines = re.compile(r'\r\n|\r') # Used in normalize_newlines
|
re_newlines = re.compile(r'\r\n|\r') # Used in normalize_newlines
|
||||||
re_camel_case = re.compile(r'(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))')
|
re_camel_case = re.compile(r'(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))')
|
||||||
|
|
|
@ -5,3 +5,17 @@ Django 1.11.23 release notes
|
||||||
*August 1, 2019*
|
*August 1, 2019*
|
||||||
|
|
||||||
Django 1.11.23 fixes security issues in 1.11.22.
|
Django 1.11.23 fixes security issues in 1.11.22.
|
||||||
|
|
||||||
|
CVE-2019-14232: Denial-of-service possibility in ``django.utils.text.Truncator``
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
If ``django.utils.text.Truncator``'s ``chars()`` and ``words()`` methods
|
||||||
|
were passed the ``html=True`` argument, they were extremely slow to evaluate
|
||||||
|
certain inputs due to a catastrophic backtracking vulnerability in a regular
|
||||||
|
expression. The ``chars()`` and ``words()`` methods are used to implement the
|
||||||
|
:tfilter:`truncatechars_html` and :tfilter:`truncatewords_html` template
|
||||||
|
filters, which were thus vulnerable.
|
||||||
|
|
||||||
|
The regular expressions used by ``Truncator`` have been simplified in order to
|
||||||
|
avoid potential backtracking issues. As a consequence, trailing punctuation may
|
||||||
|
now at times be included in the truncated output.
|
||||||
|
|
|
@ -5,3 +5,17 @@ Django 2.1.11 release notes
|
||||||
*August 1, 2019*
|
*August 1, 2019*
|
||||||
|
|
||||||
Django 2.1.11 fixes security issues in 2.1.10.
|
Django 2.1.11 fixes security issues in 2.1.10.
|
||||||
|
|
||||||
|
CVE-2019-14232: Denial-of-service possibility in ``django.utils.text.Truncator``
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
If ``django.utils.text.Truncator``'s ``chars()`` and ``words()`` methods
|
||||||
|
were passed the ``html=True`` argument, they were extremely slow to evaluate
|
||||||
|
certain inputs due to a catastrophic backtracking vulnerability in a regular
|
||||||
|
expression. The ``chars()`` and ``words()`` methods are used to implement the
|
||||||
|
:tfilter:`truncatechars_html` and :tfilter:`truncatewords_html` template
|
||||||
|
filters, which were thus vulnerable.
|
||||||
|
|
||||||
|
The regular expressions used by ``Truncator`` have been simplified in order to
|
||||||
|
avoid potential backtracking issues. As a consequence, trailing punctuation may
|
||||||
|
now at times be included in the truncated output.
|
||||||
|
|
|
@ -6,6 +6,20 @@ Django 2.2.4 release notes
|
||||||
|
|
||||||
Django 2.2.4 fixes security issues and several bugs in 2.2.3.
|
Django 2.2.4 fixes security issues and several bugs in 2.2.3.
|
||||||
|
|
||||||
|
CVE-2019-14232: Denial-of-service possibility in ``django.utils.text.Truncator``
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
If ``django.utils.text.Truncator``'s ``chars()`` and ``words()`` methods
|
||||||
|
were passed the ``html=True`` argument, they were extremely slow to evaluate
|
||||||
|
certain inputs due to a catastrophic backtracking vulnerability in a regular
|
||||||
|
expression. The ``chars()`` and ``words()`` methods are used to implement the
|
||||||
|
:tfilter:`truncatechars_html` and :tfilter:`truncatewords_html` template
|
||||||
|
filters, which were thus vulnerable.
|
||||||
|
|
||||||
|
The regular expressions used by ``Truncator`` have been simplified in order to
|
||||||
|
avoid potential backtracking issues. As a consequence, trailing punctuation may
|
||||||
|
now at times be included in the truncated output.
|
||||||
|
|
||||||
Bugfixes
|
Bugfixes
|
||||||
========
|
========
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,13 @@ class FunctionTests(SimpleTestCase):
|
||||||
def test_truncate2(self):
|
def test_truncate2(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 4),
|
truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 4),
|
||||||
'<p>one <a href="#">two - three <br>four …</a></p>',
|
'<p>one <a href="#">two - three …</a></p>',
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_truncate3(self):
|
def test_truncate3(self):
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 5),
|
truncatewords_html('<p>one <a href="#">two - three <br>four</a> five</p>', 5),
|
||||||
'<p>one <a href="#">two - three <br>four</a> five</p>',
|
'<p>one <a href="#">two - three <br>four …</a></p>',
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_truncate4(self):
|
def test_truncate4(self):
|
||||||
|
|
|
@ -88,6 +88,17 @@ class TestUtilsText(SimpleTestCase):
|
||||||
# lazy strings are handled correctly
|
# lazy strings are handled correctly
|
||||||
self.assertEqual(text.Truncator(lazystr('The quick brown fox')).chars(10), 'The quick…')
|
self.assertEqual(text.Truncator(lazystr('The quick brown fox')).chars(10), 'The quick…')
|
||||||
|
|
||||||
|
def test_truncate_chars_html(self):
|
||||||
|
perf_test_values = [
|
||||||
|
(('</a' + '\t' * 50000) + '//>', None),
|
||||||
|
('&' * 50000, '&' * 9 + '…'),
|
||||||
|
('_X<<<<<<<<<<<>', None),
|
||||||
|
]
|
||||||
|
for value, expected in perf_test_values:
|
||||||
|
with self.subTest(value=value):
|
||||||
|
truncator = text.Truncator(value)
|
||||||
|
self.assertEqual(expected if expected else value, truncator.chars(10, html=True))
|
||||||
|
|
||||||
def test_truncate_words(self):
|
def test_truncate_words(self):
|
||||||
truncator = text.Truncator('The quick brown fox jumped over the lazy dog.')
|
truncator = text.Truncator('The quick brown fox jumped over the lazy dog.')
|
||||||
self.assertEqual('The quick brown fox jumped over the lazy dog.', truncator.words(10))
|
self.assertEqual('The quick brown fox jumped over the lazy dog.', truncator.words(10))
|
||||||
|
@ -137,11 +148,17 @@ class TestUtilsText(SimpleTestCase):
|
||||||
truncator = text.Truncator('<i>Buenos días! ¿Cómo está?</i>')
|
truncator = text.Truncator('<i>Buenos días! ¿Cómo está?</i>')
|
||||||
self.assertEqual('<i>Buenos días! ¿Cómo…</i>', truncator.words(3, html=True))
|
self.assertEqual('<i>Buenos días! ¿Cómo…</i>', truncator.words(3, html=True))
|
||||||
truncator = text.Truncator('<p>I <3 python, what about you?</p>')
|
truncator = text.Truncator('<p>I <3 python, what about you?</p>')
|
||||||
self.assertEqual('<p>I <3 python…</p>', truncator.words(3, html=True))
|
self.assertEqual('<p>I <3 python,…</p>', truncator.words(3, html=True))
|
||||||
|
|
||||||
re_tag_catastrophic_test = ('</a' + '\t' * 50000) + '//>'
|
perf_test_values = [
|
||||||
truncator = text.Truncator(re_tag_catastrophic_test)
|
('</a' + '\t' * 50000) + '//>',
|
||||||
self.assertEqual(re_tag_catastrophic_test, truncator.words(500, html=True))
|
'&' * 50000,
|
||||||
|
'_X<<<<<<<<<<<>',
|
||||||
|
]
|
||||||
|
for value in perf_test_values:
|
||||||
|
with self.subTest(value=value):
|
||||||
|
truncator = text.Truncator(value)
|
||||||
|
self.assertEqual(value, truncator.words(50, html=True))
|
||||||
|
|
||||||
def test_wrap(self):
|
def test_wrap(self):
|
||||||
digits = '1234 67 9'
|
digits = '1234 67 9'
|
||||||
|
|
Loading…
Reference in New Issue