CVE-2023-30608 (published 2023-04-18T22:15Z)

sqlparse is a non-validating SQL parser module for Python. In affected versions the SQL parser contains a regular expression that is vulnerable to ReDoS (Regular Expression Denial of Service). This issue was introduced by commit `e75e358`. The vulnerability may lead to Denial of Service (DoS). This issues has been fixed in sqlparse 0.4.4 by commit `c457abd5f`. Users are advised to upgrade. There are no known workarounds for this issue.\n

CVSS v3 base score: 7.5, HIGH (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-1333
cwe_name: Inefficient Regular Expression Complexity
description: The product uses a regular expression with an inefficient, possibly exponential worst-case computational complexity that consumes excessive CPU cycles.
extended_description: Some regular expression engines have a feature called "backtracking". If the token cannot match, the engine "backtracks" to a position that may result in a different token that can match.
                Backtracking becomes a weakness if all of these conditions are met:
                
                    The number of possible backtracking attempts are exponential relative to the length of the input.
                    The input can fail to match the regular expression.
                    The input can be long enough.
                
		
		  Attackers can create crafted inputs that
		  intentionally cause the regular expression to use
		  excessive backtracking in a way that causes the CPU
		  consumption to spike.
		
            
            

Fix information:
repo_url: https://github.com/andialbrecht/sqlparse
commit_details: repo_url: https://github.com/andialbrecht/sqlparse
author: Andi Albrecht
author_date: 2023-03-20 08:33:46+01:00
msg: Remove unnecessary parts in regex for bad escaping.

The regex tried to deal with situations where escaping in the
SQL to be parsed was suspicious.
repository: repo_url: https://github.com/andialbrecht/sqlparse
repo_name: andialbrecht/sqlparse
description: A non-validating SQL parser module for Python
repo_language: Python
owner: andialbrecht
file_changes: filename: CHANGELOG
change_type: ModificationType.MODIFY
diff: @@ -1,12 +1,22 @@
 Development Version
 -------------------
 
+Notable Changes
+
+* IMPORTANT: This release fixes a security vulnerability in the
+  parser where a regular expression vulnerable to ReDOS (Regular
+  Expression Denial of Service) was used. See the security advisory
+  for details: https://github.com/andialbrecht/sqlparse/security/advisories/GHSA-rrm6-wvj7-cwh2
+  The vulnerability was discovered by @erik-krogh from GitHub
+  Security Lab (GHSL). Thanks for reporting!
+
 Bug Fixes
 
 * Revert a change from 0.4.0 that changed IN to be a comparison (issue694).
   The primary expectation is that IN is treated as a keyword and not as a
   comparison operator. That also follows the definition of reserved keywords
   for the major SQL syntax definitions.
+* Fix regular expressions for string parsing.
 
 Other
 

programming_language: Markdown
filename: keywords.py
change_type: ModificationType.MODIFY
diff: @@ -59,9 +59,9 @@ SQL_REGEX = [
     (r'(?![_A-ZÀ-Ü])-?(\d+(\.\d*)|\.\d+)(?![_A-ZÀ-Ü])',
      tokens.Number.Float),
     (r'(?![_A-ZÀ-Ü])-?\d+(?![_A-ZÀ-Ü])', tokens.Number.Integer),
-    (r"'(''|\\\\|\\'|[^'])*'", tokens.String.Single),
+    (r"'(''|\\'|[^'])*'", tokens.String.Single),
     # not a real string literal in ANSI SQL:
-    (r'"(""|\\\\|\\"|[^"])*"', tokens.String.Symbol),
+    (r'"(""|\\"|[^"])*"', tokens.String.Symbol),
     (r'(""|".*?[^\\]")', tokens.String.Symbol),
     # sqlite names can be escaped with [square brackets]. left bracket
     # cannot be preceded by word character or a right bracket --

programming_language: JavaScript
filename: test_split.py
change_type: ModificationType.MODIFY
diff: @@ -18,8 +18,8 @@ def test_split_semicolon():
 
 
 def test_split_backslash():
-    stmts = sqlparse.parse(r"select '\\'; select '\''; select '\\\'';")
-    assert len(stmts) == 3
+    stmts = sqlparse.parse("select '\'; select '\'';")
+    assert len(stmts) == 2
 
 
 @pytest.mark.parametrize('fn', ['function.sql',

programming_language: Python
repo_url: https://github.com/andialbrecht/sqlparse
commit_details: repo_url: https://github.com/andialbrecht/sqlparse
author: casey
author_date: 2015-02-26 12:32:46-08:00
msg: Recognize escaped backslashes within strings

Previously if a single quoted string ended with an escaped backslash,
parsing would not consider the string to be terminated.
repository: repo_url: https://github.com/andialbrecht/sqlparse
repo_name: andialbrecht/sqlparse
description: A non-validating SQL parser module for Python
repo_language: Python
owner: andialbrecht
file_changes: filename: lexer.py
change_type: ModificationType.MODIFY
diff: @@ -191,8 +191,7 @@ class Lexer(object):
             (r'[-]?[0-9]*(\.[0-9]+)?[eE][-]?[0-9]+', tokens.Number.Float),
             (r'[-]?[0-9]*\.[0-9]+', tokens.Number.Float),
             (r'[-]?[0-9]+', tokens.Number.Integer),
-            # TODO: Backslash escapes?
-            (r"'(''|\\'|[^'])*'", tokens.String.Single),
+            (r"'(''|\\\\|\\'|[^'])*'", tokens.String.Single),
             # not a real string literal in ANSI SQL:
             (r'(""|".*?[^\\]")', tokens.String.Symbol),
             (r'(?<=[\w\]])(\[[^\]]*?\])', tokens.Punctuation.ArrayIndex),

programming_language: Python
filename: test_split.py
change_type: ModificationType.MODIFY
diff: @@ -22,6 +22,10 @@ class SQLSplitTest(TestCaseBase):
         self.ndiffAssertEqual(unicode(stmts[0]), self._sql1)
         self.ndiffAssertEqual(unicode(stmts[1]), sql2)
 
+    def test_split_backslash(self):
+        stmts = sqlparse.parse(r"select '\\'; select '\''; select '\\\'';")
+        self.assertEqual(len(stmts), 3)
+
     def test_create_function(self):
         sql = load_file('function.sql')
         stmts = sqlparse.parse(sql)

programming_language: Python