https://github.com/python/cpython/commit/af2f5189a12888afa4e93243653c331e9fffddb5 commit: af2f5189a12888afa4e93243653c331e9fffddb5 branch: 3.14 author: Miss Islington (bot) <[email protected]> committer: gpshead <[email protected]> date: 2026-04-12T00:05:10Z summary:
[3.14] gh-146333: Fix quadratic regex backtracking in configparser option parsing (GH-146399) (#148287) gh-146333: Fix quadratic regex backtracking in configparser option parsing (GH-146399) Use negative lookahead in option regex to prevent backtracking, and to avoid changing logic outside the regexes (since people could use the regex directly). (cherry picked from commit 7e0a0be4097f9d29d66fe23f5af86f18a34ed7dd) Co-authored-by: Joshua Swanson <[email protected]> files: A Misc/NEWS.d/next/Security/2026-03-25-00-51-03.gh-issue-146333.LqdL__bn.rst M Lib/configparser.py M Lib/test/test_configparser.py diff --git a/Lib/configparser.py b/Lib/configparser.py index d435a5c2fe0da2..e76647d339e913 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -613,7 +613,9 @@ class RawConfigParser(MutableMapping): \] # ] """ _OPT_TMPL = r""" - (?P<option>.*?) # very permissive! + (?P<option> # very permissive! + (?:(?!{delim})\S)* # non-delimiter non-whitespace + (?:\s+(?:(?!{delim})\S)+)*) # optionally more words \s*(?P<vi>{delim})\s* # any number of space/tab, # followed by any of the # allowed delimiters, @@ -621,7 +623,9 @@ class RawConfigParser(MutableMapping): (?P<value>.*)$ # everything up to eol """ _OPT_NV_TMPL = r""" - (?P<option>.*?) # very permissive! + (?P<option> # very permissive! + (?:(?!{delim})\S)* # non-delimiter non-whitespace + (?:\s+(?:(?!{delim})\S)+)*) # optionally more words \s*(?: # any number of space/tab, (?P<vi>{delim})\s* # optionally followed by # any of the allowed diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index 1bfb53ccbb1398..d7c4f19c1a5ef0 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -2270,6 +2270,26 @@ def test_section_bracket_in_key(self): output.close() +class ReDoSTestCase(unittest.TestCase): + """Regression tests for quadratic regex backtracking (gh-146333).""" + + def test_option_regex_does_not_backtrack(self): + # A line with many spaces between non-delimiter characters + # should be parsed in linear time, not quadratic. + parser = configparser.RawConfigParser() + content = "[section]\n" + "x" + " " * 40000 + "y" + "\n" + # This should complete almost instantly. Before the fix, + # it would take over a minute due to catastrophic backtracking. + with self.assertRaises(configparser.ParsingError): + parser.read_string(content) + + def test_option_regex_no_value_does_not_backtrack(self): + parser = configparser.RawConfigParser(allow_no_value=True) + content = "[section]\n" + "x" + " " * 40000 + "y" + "\n" + parser.read_string(content) + self.assertTrue(parser.has_option("section", "x" + " " * 40000 + "y")) + + class MiscTestCase(unittest.TestCase): def test__all__(self): support.check__all__(self, configparser, not_exported={"Error"}) diff --git a/Misc/NEWS.d/next/Security/2026-03-25-00-51-03.gh-issue-146333.LqdL__bn.rst b/Misc/NEWS.d/next/Security/2026-03-25-00-51-03.gh-issue-146333.LqdL__bn.rst new file mode 100644 index 00000000000000..96d86ecc0a0fb3 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-03-25-00-51-03.gh-issue-146333.LqdL__bn.rst @@ -0,0 +1,3 @@ +Fix quadratic backtracking in :class:`configparser.RawConfigParser` option +parsing regexes (``OPTCRE`` and ``OPTCRE_NV``). A crafted configuration line +with many whitespace characters could cause excessive CPU usage. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
