[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 7e0a0be409)

Co-authored-by: Joshua Swanson <22283299+joshuaswanson@users.noreply.github.com>
This commit is contained in:
Miss Islington (bot) 2026-04-12 02:05:10 +02:00 committed by GitHub
parent 4f8a77bf3f
commit af2f5189a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 29 additions and 2 deletions

View file

@ -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

View file

@ -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"})

View file

@ -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.