Skip to content

Commit b4a39d9

Browse files
committed
Raise SQLParseError instead of RecursionError.
1 parent f1bcf2f commit b4a39d9

File tree

3 files changed

+30
-6
lines changed

3 files changed

+30
-6
lines changed

CHANGELOG

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ Notable Changes
55

66
* Drop support for Python 3.5, 3.6, and 3.7.
77
* Python 3.12 is now supported (pr725, by hugovk).
8+
* IMPORTANT: Fixes a potential denial of service attack (DOS) due to recursion
9+
error for deeply nested statements. Instead of recursion error a generic
10+
SQLParseError is raised. See the security advisory for details:
11+
https://github.com/andialbrecht/sqlparse/security/advisories/GHSA-2m57-hf25-phgg
12+
The vulnerability was discovered by @uriyay-jfrog. Thanks for reporting!
813

914
Enhancements:
1015

sqlparse/sql.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import re
1111

1212
from sqlparse import tokens as T
13+
from sqlparse.exceptions import SQLParseError
1314
from sqlparse.utils import imt, remove_quotes
1415

1516

@@ -209,11 +210,14 @@ def flatten(self):
209210
210211
This method is recursively called for all child tokens.
211212
"""
212-
for token in self.tokens:
213-
if token.is_group:
214-
yield from token.flatten()
215-
else:
216-
yield token
213+
try:
214+
for token in self.tokens:
215+
if token.is_group:
216+
yield from token.flatten()
217+
else:
218+
yield token
219+
except RecursionError as err:
220+
raise SQLParseError('Maximum recursion depth exceeded') from err
217221

218222
def get_sublists(self):
219223
for token in self.tokens:

tests/test_regressions.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import copy
2+
import sys
23

34
import pytest
45

56
import sqlparse
67
from sqlparse import sql, tokens as T
8+
from sqlparse.exceptions import SQLParseError
79

810

911
def test_issue9():
@@ -449,4 +451,17 @@ def test_copy_issue672():
449451
def test_primary_key_issue740():
450452
p = sqlparse.parse('PRIMARY KEY')[0]
451453
assert len(p.tokens) == 1
452-
assert p.tokens[0].ttype == T.Keyword
454+
assert p.tokens[0].ttype == T.Keyword
455+
456+
457+
@pytest.fixture
458+
def limit_recursion():
459+
curr_limit = sys.getrecursionlimit()
460+
sys.setrecursionlimit(70)
461+
yield
462+
sys.setrecursionlimit(curr_limit)
463+
464+
465+
def test_max_recursion(limit_recursion):
466+
with pytest.raises(SQLParseError):
467+
sqlparse.parse('[' * 100 + ']' * 100)

0 commit comments

Comments
 (0)