Skip to content

Commit 52fbae0

Browse files
felixxmjacobtylerwalls
authored andcommitted
[5.2.x] Fixed CVE-2025-59681 -- Protected QuerySet.annotate(), alias(), aggregate(), and extra() against SQL injection in column aliases on MySQL/MariaDB.
Thanks sw0rd1ight for the report. Follow up to 93cae5c. Backport of 41b43c7 from main.
1 parent 1794cbf commit 52fbae0

8 files changed

Lines changed: 49 additions & 25 deletions

File tree

django/db/models/sql/query.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@
4848

4949
__all__ = ["Query", "RawQuery"]
5050

51-
# Quotation marks ('"`[]), whitespace characters, semicolons, or inline
51+
# Quotation marks ('"`[]), whitespace characters, semicolons, hashes, or inline
5252
# SQL comments are forbidden in column aliases.
53-
FORBIDDEN_ALIAS_PATTERN = _lazy_re_compile(r"['`\"\]\[;\s]|--|/\*|\*/")
53+
FORBIDDEN_ALIAS_PATTERN = _lazy_re_compile(r"['`\"\]\[;\s]|#|--|/\*|\*/")
5454

5555
# Inspired from
5656
# https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
@@ -1208,8 +1208,8 @@ def join_parent_model(self, opts, model, alias, seen):
12081208
def check_alias(self, alias):
12091209
if FORBIDDEN_ALIAS_PATTERN.search(alias):
12101210
raise ValueError(
1211-
"Column aliases cannot contain whitespace characters, quotation marks, "
1212-
"semicolons, or SQL comments."
1211+
"Column aliases cannot contain whitespace characters, hashes, "
1212+
"quotation marks, semicolons, or SQL comments."
12131213
)
12141214

12151215
def add_annotation(self, annotation, alias, select=True):

docs/releases/4.2.25.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,11 @@ Django 4.2.25 release notes
77
Django 4.2.25 fixes one security issue with severity "high" and one security
88
issue with severity "low" in 4.2.24.
99

10-
...
10+
CVE-2025-59681: Potential SQL injection in ``QuerySet.annotate()``, ``alias()``, ``aggregate()``, and ``extra()`` on MySQL and MariaDB
11+
======================================================================================================================================
12+
13+
:meth:`.QuerySet.annotate`, :meth:`~.QuerySet.alias`,
14+
:meth:`~.QuerySet.aggregate`, and :meth:`~.QuerySet.extra` methods were subject
15+
to SQL injection in column aliases, using a suitably crafted dictionary, with
16+
dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to
17+
:cve:`2022-28346`).

docs/releases/5.1.13.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,11 @@ Django 5.1.13 release notes
77
Django 5.1.13 fixes one security issue with severity "high" and one security
88
issue with severity "low" in 5.1.12.
99

10-
...
10+
CVE-2025-59681: Potential SQL injection in ``QuerySet.annotate()``, ``alias()``, ``aggregate()``, and ``extra()`` on MySQL and MariaDB
11+
======================================================================================================================================
12+
13+
:meth:`.QuerySet.annotate`, :meth:`~.QuerySet.alias`,
14+
:meth:`~.QuerySet.aggregate`, and :meth:`~.QuerySet.extra` methods were subject
15+
to SQL injection in column aliases, using a suitably crafted dictionary, with
16+
dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to
17+
:cve:`2022-28346`).

docs/releases/5.2.7.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ Django 5.2.7 fixes one security issue with severity "high", one security issue
88
with severity "low", and one bug in 5.2.6. Also, the latest string translations
99
from Transifex are incorporated.
1010

11+
CVE-2025-59681: Potential SQL injection in ``QuerySet.annotate()``, ``alias()``, ``aggregate()``, and ``extra()`` on MySQL and MariaDB
12+
======================================================================================================================================
13+
14+
:meth:`.QuerySet.annotate`, :meth:`~.QuerySet.alias`,
15+
:meth:`~.QuerySet.aggregate`, and :meth:`~.QuerySet.extra` methods were subject
16+
to SQL injection in column aliases, using a suitably crafted dictionary, with
17+
dictionary expansion, as the ``**kwargs`` passed to these methods (follow up to
18+
:cve:`2022-28346`).
19+
1120
Bugfixes
1221
========
1322

tests/aggregation/tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,8 +2136,8 @@ def test_exists_none_with_aggregate(self):
21362136
def test_alias_sql_injection(self):
21372137
crafted_alias = """injected_name" from "aggregation_author"; --"""
21382138
msg = (
2139-
"Column aliases cannot contain whitespace characters, quotation marks, "
2140-
"semicolons, or SQL comments."
2139+
"Column aliases cannot contain whitespace characters, hashes, quotation "
2140+
"marks, semicolons, or SQL comments."
21412141
)
21422142
with self.assertRaisesMessage(ValueError, msg):
21432143
Author.objects.aggregate(**{crafted_alias: Avg("age")})

tests/annotations/tests.py

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,17 +1159,17 @@ def test_annotation_aggregate_with_m2o(self):
11591159
def test_alias_sql_injection(self):
11601160
crafted_alias = """injected_name" from "annotations_book"; --"""
11611161
msg = (
1162-
"Column aliases cannot contain whitespace characters, quotation marks, "
1163-
"semicolons, or SQL comments."
1162+
"Column aliases cannot contain whitespace characters, hashes, quotation "
1163+
"marks, semicolons, or SQL comments."
11641164
)
11651165
with self.assertRaisesMessage(ValueError, msg):
11661166
Book.objects.annotate(**{crafted_alias: Value(1)})
11671167

11681168
def test_alias_filtered_relation_sql_injection(self):
11691169
crafted_alias = """injected_name" from "annotations_book"; --"""
11701170
msg = (
1171-
"Column aliases cannot contain whitespace characters, quotation marks, "
1172-
"semicolons, or SQL comments."
1171+
"Column aliases cannot contain whitespace characters, hashes, quotation "
1172+
"marks, semicolons, or SQL comments."
11731173
)
11741174
with self.assertRaisesMessage(ValueError, msg):
11751175
Book.objects.annotate(**{crafted_alias: FilteredRelation("author")})
@@ -1186,13 +1186,14 @@ def test_alias_forbidden_chars(self):
11861186
"ali/*as",
11871187
"alias*/",
11881188
"alias;",
1189-
# [] are used by MSSQL.
1189+
# [] and # are used by MSSQL.
11901190
"alias[",
11911191
"alias]",
1192+
"ali#as",
11921193
]
11931194
msg = (
1194-
"Column aliases cannot contain whitespace characters, quotation marks, "
1195-
"semicolons, or SQL comments."
1195+
"Column aliases cannot contain whitespace characters, hashes, quotation "
1196+
"marks, semicolons, or SQL comments."
11961197
)
11971198
for crafted_alias in tests:
11981199
with self.subTest(crafted_alias):
@@ -1492,17 +1493,17 @@ def test_alias_after_values(self):
14921493
def test_alias_sql_injection(self):
14931494
crafted_alias = """injected_name" from "annotations_book"; --"""
14941495
msg = (
1495-
"Column aliases cannot contain whitespace characters, quotation marks, "
1496-
"semicolons, or SQL comments."
1496+
"Column aliases cannot contain whitespace characters, hashes, quotation "
1497+
"marks, semicolons, or SQL comments."
14971498
)
14981499
with self.assertRaisesMessage(ValueError, msg):
14991500
Book.objects.alias(**{crafted_alias: Value(1)})
15001501

15011502
def test_alias_filtered_relation_sql_injection(self):
15021503
crafted_alias = """injected_name" from "annotations_book"; --"""
15031504
msg = (
1504-
"Column aliases cannot contain whitespace characters, quotation marks, "
1505-
"semicolons, or SQL comments."
1505+
"Column aliases cannot contain whitespace characters, hashes, quotation "
1506+
"marks, semicolons, or SQL comments."
15061507
)
15071508
with self.assertRaisesMessage(ValueError, msg):
15081509
Book.objects.alias(**{crafted_alias: FilteredRelation("authors")})

tests/expressions/test_queryset_values.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ def test_values_expression(self):
3737
def test_values_expression_alias_sql_injection(self):
3838
crafted_alias = """injected_name" from "expressions_company"; --"""
3939
msg = (
40-
"Column aliases cannot contain whitespace characters, quotation marks, "
41-
"semicolons, or SQL comments."
40+
"Column aliases cannot contain whitespace characters, hashes, quotation "
41+
"marks, semicolons, or SQL comments."
4242
)
4343
with self.assertRaisesMessage(ValueError, msg):
4444
Company.objects.values(**{crafted_alias: F("ceo__salary")})
@@ -47,8 +47,8 @@ def test_values_expression_alias_sql_injection(self):
4747
def test_values_expression_alias_sql_injection_json_field(self):
4848
crafted_alias = """injected_name" from "expressions_company"; --"""
4949
msg = (
50-
"Column aliases cannot contain whitespace characters, quotation marks, "
51-
"semicolons, or SQL comments."
50+
"Column aliases cannot contain whitespace characters, hashes, quotation "
51+
"marks, semicolons, or SQL comments."
5252
)
5353
with self.assertRaisesMessage(ValueError, msg):
5454
JSONFieldModel.objects.values(f"data__{crafted_alias}")

tests/queries/tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,8 +1961,8 @@ def test_extra_select_literal_percent_s(self):
19611961
def test_extra_select_alias_sql_injection(self):
19621962
crafted_alias = """injected_name" from "queries_note"; --"""
19631963
msg = (
1964-
"Column aliases cannot contain whitespace characters, quotation marks, "
1965-
"semicolons, or SQL comments."
1964+
"Column aliases cannot contain whitespace characters, hashes, quotation "
1965+
"marks, semicolons, or SQL comments."
19661966
)
19671967
with self.assertRaisesMessage(ValueError, msg):
19681968
Note.objects.extra(select={crafted_alias: "1"})

0 commit comments

Comments
 (0)