Skip to content

Commit a34a5f7

Browse files
charettesfelixxm
authored andcommitted
[3.2.x] Fixed CVE-2021-35042 -- Prevented SQL injection in QuerySet.order_by().
Regression introduced in 5139487 by marking the raw SQL column reference feature for deprecation in Django 4.0 while lifting the column format validation. In retrospective the validation should have been kept around and the user should have been pointed at using RawSQL expressions during the deprecation period. The main branch is not affected because the raw SQL column reference support has been removed in 06eec31 per the 4.0 deprecation life cycle. Thanks Joel Saunders for the report.
1 parent da2269d commit a34a5f7

File tree

5 files changed

+43
-5
lines changed

5 files changed

+43
-5
lines changed

django/db/models/sql/constants.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Constants specific to the SQL storage portion of the ORM.
33
"""
4+
from django.utils.regex_helper import _lazy_re_compile
45

56
# Size of each "chunk" for get_iterator calls.
67
# Larger values are slightly faster at the expense of more storage space.
@@ -18,6 +19,7 @@
1819
'ASC': ('ASC', 'DESC'),
1920
'DESC': ('DESC', 'ASC'),
2021
}
22+
ORDER_PATTERN = _lazy_re_compile(r'[-+]?[.\w]+$')
2123

2224
# SQL join types.
2325
INNER = 'INNER JOIN'

django/db/models/sql/query.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@
3030
from django.db.models.query_utils import (
3131
Q, check_rel_lookup_compatibility, refs_expression,
3232
)
33-
from django.db.models.sql.constants import INNER, LOUTER, ORDER_DIR, SINGLE
33+
from django.db.models.sql.constants import (
34+
INNER, LOUTER, ORDER_DIR, ORDER_PATTERN, SINGLE,
35+
)
3436
from django.db.models.sql.datastructures import (
3537
BaseTable, Empty, Join, MultiJoin,
3638
)
@@ -1969,7 +1971,7 @@ def add_ordering(self, *ordering):
19691971
errors = []
19701972
for item in ordering:
19711973
if isinstance(item, str):
1972-
if '.' in item:
1974+
if '.' in item and ORDER_PATTERN.match(item):
19731975
warnings.warn(
19741976
'Passing column raw column aliases to order_by() is '
19751977
'deprecated. Wrap %r in a RawSQL expression before '

docs/releases/3.1.13.txt

+13-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,16 @@ Django 3.1.13 release notes
66

77
Django 3.1.13 fixes a security issues with severity "high" in 3.1.12.
88

9-
...
9+
CVE-2021-35042: Potential SQL injection via unsanitized ``QuerySet.order_by()`` input
10+
=====================================================================================
11+
12+
Unsanitized user input passed to ``QuerySet.order_by()`` could bypass intended
13+
column reference validation in path marked for deprecation resulting in a
14+
potential SQL injection even if a deprecation warning is emitted.
15+
16+
As a mitigation the strict column reference validation was restored for the
17+
duration of the deprecation period. This regression appeared in 3.1 as a side
18+
effect of fixing :ticket:`31426`.
19+
20+
The issue is not present in the main branch as the deprecated path has been
21+
removed.

docs/releases/3.2.5.txt

+16-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,22 @@ Django 3.2.5 release notes
44

55
*July 1, 2021*
66

7-
Django 3.2.5 fixes several bugs in 3.2.4. Also, the latest string translations
8-
from Transifex are incorporated.
7+
Django 3.2.5 fixes a security issue with severity "high" and several bugs in
8+
3.2.4. Also, the latest string translations from Transifex are incorporated.
9+
10+
CVE-2021-35042: Potential SQL injection via unsanitized ``QuerySet.order_by()`` input
11+
=====================================================================================
12+
13+
Unsanitized user input passed to ``QuerySet.order_by()`` could bypass intended
14+
column reference validation in path marked for deprecation resulting in a
15+
potential SQL injection even if a deprecation warning is emitted.
16+
17+
As a mitigation the strict column reference validation was restored for the
18+
duration of the deprecation period. This regression appeared in 3.1 as a side
19+
effect of fixing :ticket:`31426`.
20+
21+
The issue is not present in the main branch as the deprecated path has been
22+
removed.
923

1024
Bugfixes
1125
========

tests/queries/tests.py

+8
Original file line numberDiff line numberDiff line change
@@ -3116,6 +3116,14 @@ def test_invalid_order_by(self):
31163116
with self.assertRaisesMessage(FieldError, msg):
31173117
Article.objects.order_by('*')
31183118

3119+
def test_order_by_escape_prevention(self):
3120+
msg = (
3121+
"Cannot resolve keyword 'queries.name);' into field. Choices are: "
3122+
"created, id, name"
3123+
)
3124+
with self.assertRaisesMessage(FieldError, msg):
3125+
Article.objects.order_by('queries.name);')
3126+
31193127
def test_invalid_queryset_model(self):
31203128
msg = 'Cannot use QuerySet for "Article": Use a QuerySet for "ExtraInfo".'
31213129
with self.assertRaisesMessage(ValueError, msg):

0 commit comments

Comments
 (0)