Skip to content

Commit

Permalink
Raise SQLParseError instead of RecursionError.
Browse files Browse the repository at this point in the history
  • Loading branch information
andialbrecht committed Apr 13, 2024
1 parent f1bcf2f commit b4a39d9
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 6 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ Notable Changes

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

Enhancements:

Expand Down
14 changes: 9 additions & 5 deletions sqlparse/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import re

from sqlparse import tokens as T
from sqlparse.exceptions import SQLParseError
from sqlparse.utils import imt, remove_quotes


Expand Down Expand Up @@ -209,11 +210,14 @@ def flatten(self):
This method is recursively called for all child tokens.
"""
for token in self.tokens:
if token.is_group:
yield from token.flatten()
else:
yield token
try:
for token in self.tokens:
if token.is_group:
yield from token.flatten()
else:
yield token
except RecursionError as err:
raise SQLParseError('Maximum recursion depth exceeded') from err

def get_sublists(self):
for token in self.tokens:
Expand Down
17 changes: 16 additions & 1 deletion tests/test_regressions.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import copy
import sys

import pytest

import sqlparse
from sqlparse import sql, tokens as T
from sqlparse.exceptions import SQLParseError


def test_issue9():
Expand Down Expand Up @@ -449,4 +451,17 @@ def test_copy_issue672():
def test_primary_key_issue740():
p = sqlparse.parse('PRIMARY KEY')[0]
assert len(p.tokens) == 1
assert p.tokens[0].ttype == T.Keyword
assert p.tokens[0].ttype == T.Keyword


@pytest.fixture
def limit_recursion():
curr_limit = sys.getrecursionlimit()
sys.setrecursionlimit(70)
yield
sys.setrecursionlimit(curr_limit)


def test_max_recursion(limit_recursion):
with pytest.raises(SQLParseError):
sqlparse.parse('[' * 100 + ']' * 100)

0 comments on commit b4a39d9

Please sign in to comment.