Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 55d5bfb

Browse files
davisjambenjaminp
authored andcommitted
[2.7] closes bpo-32997: Fix REDOS in fpformat (pythonGH-5984)
The regex to decode a number in fpformat is susceptible to catastrophic backtracking. This is a potential DOS vector if a server is using fpformat on untrusted number strings. Replace it with an equivalent non-vulnerable regex. The match behavior of the new regex is slightly different. It captures the whole integer part of the number in one group, Leading zeros are stripped off later.
1 parent e052d40 commit 55d5bfb

File tree

3 files changed

+16
-1
lines changed

3 files changed

+16
-1
lines changed

Lib/fpformat.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
__all__ = ["fix","sci","NotANumber"]
2020

2121
# Compiled regular expression to "decode" a number
22-
decoder = re.compile(r'^([-+]?)0*(\d*)((?:\.\d*)?)(([eE][-+]?\d+)?)$')
22+
decoder = re.compile(r'^([-+]?)(\d*)((?:\.\d*)?)(([eE][-+]?\d+)?)$')
2323
# \0 the whole thing
2424
# \1 leading sign or empty
2525
# \2 digits left of decimal point
@@ -41,6 +41,7 @@ def extract(s):
4141
res = decoder.match(s)
4242
if res is None: raise NotANumber, s
4343
sign, intpart, fraction, exppart = res.group(1,2,3,4)
44+
intpart = intpart.lstrip('0');
4445
if sign == '+': sign = ''
4546
if fraction: fraction = fraction[1:]
4647
if exppart: expo = int(exppart[1:])

Lib/test/test_fpformat.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,16 @@ def test_failing_values(self):
6767
else:
6868
self.fail("No exception on non-numeric sci")
6969

70+
def test_REDOS(self):
71+
# This attack string will hang on the old decoder pattern.
72+
attack = '+0' + ('0' * 1000000) + '++'
73+
digs = 5 # irrelevant
74+
75+
# fix returns input if it does not decode
76+
self.assertEqual(fpformat.fix(attack, digs), attack)
77+
# sci raises NotANumber
78+
with self.assertRaises(NotANumber):
79+
fpformat.sci(attack, digs)
7080

7181
def test_main():
7282
run_unittest(FpformatTest)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
A regex in fpformat was vulnerable to catastrophic backtracking. This regex
2+
was a potential DOS vector (REDOS). Based on typical uses of fpformat the
3+
risk seems low. The regex has been refactored and is now safe. Patch by
4+
Jamie Davis.

0 commit comments

Comments
 (0)