Skip to content

Commit 1f42f82

Browse files
committed
[2.0.x] Fixed CVE-2019-6975 -- Fixed memory exhaustion in utils.numberformat.format().
Thanks Sjoerd Job Postmus for the report and initial patch. Thanks Michael Manfre, Tim Graham, and Florian Apolloner for review.
1 parent f6f0f52 commit 1f42f82

File tree

4 files changed

+57
-1
lines changed

4 files changed

+57
-1
lines changed

django/utils/numberformat.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,20 @@ def format(number, decimal_sep, decimal_pos=None, grouping=0, thousand_sep='',
2727
# sign
2828
sign = ''
2929
if isinstance(number, Decimal):
30-
str_number = '{:f}'.format(number)
30+
# Format values with more than 200 digits (an arbitrary cutoff) using
31+
# scientific notation to avoid high memory usage in {:f}'.format().
32+
_, digits, exponent = number.as_tuple()
33+
if abs(exponent) + len(digits) > 200:
34+
number = '{:e}'.format(number)
35+
coefficient, exponent = number.split('e')
36+
# Format the coefficient.
37+
coefficient = format(
38+
coefficient, decimal_sep, decimal_pos, grouping,
39+
thousand_sep, force_grouping, use_l10n,
40+
)
41+
return '{}e{}'.format(coefficient, exponent)
42+
else:
43+
str_number = '{:f}'.format(number)
3144
else:
3245
str_number = str(number)
3346
if str_number[0] == '-':

docs/releases/1.11.19.txt

+12
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,15 @@ Django 1.11.19 release notes
55
*February 11, 2019*
66

77
Django 1.11.19 fixes a security issue in 1.11.18.
8+
9+
CVE-2019-6975: Memory exhaustion in ``django.utils.numberformat.format()``
10+
--------------------------------------------------------------------------
11+
12+
If ``django.utils.numberformat.format()`` -- used by ``contrib.admin`` as well
13+
as the the ``floatformat``, ``filesizeformat``, and ``intcomma`` templates
14+
filters -- received a ``Decimal`` with a large number of digits or a large
15+
exponent, it could lead to significant memory usage due to a call to
16+
``'{:f}'.format()``.
17+
18+
To avoid this, decimals with more than 200 digits are now formatted using
19+
scientific notation.

docs/releases/2.0.11.txt

+12
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,15 @@ Django 2.0.11 release notes
55
*February 11, 2019*
66

77
Django 2.0.11 fixes a security issue in 2.0.10.
8+
9+
CVE-2019-6975: Memory exhaustion in ``django.utils.numberformat.format()``
10+
--------------------------------------------------------------------------
11+
12+
If ``django.utils.numberformat.format()`` -- used by ``contrib.admin`` as well
13+
as the the ``floatformat``, ``filesizeformat``, and ``intcomma`` templates
14+
filters -- received a ``Decimal`` with a large number of digits or a large
15+
exponent, it could lead to significant memory usage due to a call to
16+
``'{:f}'.format()``.
17+
18+
To avoid this, decimals with more than 200 digits are now formatted using
19+
scientific notation.

tests/utils_tests/test_numberformat.py

+19
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,25 @@ def test_decimal_numbers(self):
7575
)
7676
self.assertEqual(nformat(Decimal('3.'), '.'), '3')
7777
self.assertEqual(nformat(Decimal('3.0'), '.'), '3.0')
78+
# Very large & small numbers.
79+
tests = [
80+
('9e9999', None, '9e+9999'),
81+
('9e9999', 3, '9.000e+9999'),
82+
('9e201', None, '9e+201'),
83+
('9e200', None, '9e+200'),
84+
('1.2345e999', 2, '1.23e+999'),
85+
('9e-999', None, '9e-999'),
86+
('1e-7', 8, '0.00000010'),
87+
('1e-8', 8, '0.00000001'),
88+
('1e-9', 8, '0.00000000'),
89+
('1e-10', 8, '0.00000000'),
90+
('1e-11', 8, '0.00000000'),
91+
('1' + ('0' * 300), 3, '1.000e+300'),
92+
('0.{}1234'.format('0' * 299), 3, '1.234e-300'),
93+
]
94+
for value, decimal_pos, expected_value in tests:
95+
with self.subTest(value=value):
96+
self.assertEqual(nformat(Decimal(value), '.', decimal_pos), expected_value)
7897

7998
def test_decimal_subclass(self):
8099
class EuroDecimal(Decimal):

0 commit comments

Comments
 (0)