[3.10] gh-146333: Fix quadratic regex backtracking in configparser option parsing (GH-146399) (GH-148559) (#154878)

pablogsal <[email protected]> Mon, 10 Aug 2026 15:55:09 -0400 (EDT)
Newsgroups gmane.comp.python.cvs
Message-ID <[email protected]>
https://github.com/python/cpython/commit/0e14e5db4ccbcdd339aa0ccf81ca1fa5c4c2f6b6
commit: 0e14e5db4ccbcdd339aa0ccf81ca1fa5c4c2f6b6
branch: 3.10
author: Petr Viktorin <[email protected]>
committer: pablogsal <[email protected]>
date: 2026-08-10T20:53:58+01:00
summary:

[3.10] gh-146333: Fix quadratic regex backtracking in configparser option parsing (GH-146399) (GH-148559) (#154878)

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)


(cherry picked from commit a5969e8f0fda37aaf0e2f844fdcfca9d822a70b1)

Co-authored-by: Joshua Swanson <[email protected]>
Co-authored-by: Hugo van Kemenade <[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 785527082d07a0..7c85f3ff9fbae1 100644
--- a/Lib/configparser.py
+++ b/Lib/configparser.py
@@ -568,7 +568,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,
@@ -576,7 +578,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 e9b03e6c62ef14..0e738126db34ea 100644
--- a/Lib/test/test_configparser.py
+++ b/Lib/test/test_configparser.py
@@ -2133,6 +2133,26 @@ def test_instance_assignment(self):
             self.assertEqual(cfg['two'].getlen('one'), 5)
 
 
+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]