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

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

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

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

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

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 17707b745f716e..ff581c6e805bfa 100644
--- a/Lib/configparser.py
+++ b/Lib/configparser.py
@@ -577,7 +577,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,
@@ -585,7 +587,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 f69e39f5c63919..bbd3d8ae74a968 100644
--- a/Lib/test/test_configparser.py
+++ b/Lib/test/test_configparser.py
@@ -2166,6 +2166,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]