[1.11.x] Fixed CVE-2020-7471 -- Properly escaped StringAgg(delimiter) parameter.

This commit is contained in:
Carlton Gibson 2020-01-22 09:03:27 +01:00
parent 7fd1ca3ef6
commit 001b0634cd
4 changed files with 22 additions and 2 deletions

View File

@ -1,4 +1,5 @@
from django.contrib.postgres.fields import JSONField from django.contrib.postgres.fields import JSONField
from django.db.models import Value
from django.db.models.aggregates import Aggregate from django.db.models.aggregates import Aggregate
__all__ = [ __all__ = [
@ -43,11 +44,12 @@ class JSONBAgg(Aggregate):
class StringAgg(Aggregate): class StringAgg(Aggregate):
function = 'STRING_AGG' function = 'STRING_AGG'
template = "%(function)s(%(distinct)s%(expressions)s, '%(delimiter)s')" template = '%(function)s(%(distinct)s%(expressions)s)'
def __init__(self, expression, delimiter, distinct=False, **extra): def __init__(self, expression, delimiter, distinct=False, **extra):
distinct = 'DISTINCT ' if distinct else '' distinct = 'DISTINCT ' if distinct else ''
super(StringAgg, self).__init__(expression, delimiter=delimiter, distinct=distinct, **extra) delimiter_expr = Value(str(delimiter))
super(StringAgg, self).__init__(expression, delimiter_expr, distinct=distinct, **extra)
def convert_value(self, value, expression, connection, context): def convert_value(self, value, expression, connection, context):
if not value: if not value:

13
docs/releases/1.11.28.txt Normal file
View File

@ -0,0 +1,13 @@
============================
Django 1.11.28 release notes
============================
*February 3, 2020*
Django 1.11.28 fixes a security issue in 1.11.27.
CVE-2020-7471: Potential SQL injection via ``StringAgg(delimiter)``
===================================================================
:class:`~django.contrib.postgres.aggregates.StringAgg` aggregation function was
subject to SQL injection, using a suitably crafted ``delimiter``.

View File

@ -26,6 +26,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree:: .. toctree::
:maxdepth: 1 :maxdepth: 1
1.11.28
1.11.27 1.11.27
1.11.26 1.11.26
1.11.25 1.11.25

View File

@ -108,6 +108,10 @@ class TestGeneralAggregate(PostgreSQLTestCase):
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
AggregateTestModel.objects.aggregate(stringagg=StringAgg('char_field')) AggregateTestModel.objects.aggregate(stringagg=StringAgg('char_field'))
def test_string_agg_delimiter_escaping(self):
values = AggregateTestModel.objects.aggregate(stringagg=StringAgg('char_field', delimiter="'"))
self.assertEqual(values, {'stringagg': "Foo1'Foo2'Foo3'Foo4"})
def test_string_agg_charfield(self): def test_string_agg_charfield(self):
values = AggregateTestModel.objects.aggregate(stringagg=StringAgg('char_field', delimiter=';')) values = AggregateTestModel.objects.aggregate(stringagg=StringAgg('char_field', delimiter=';'))
self.assertEqual(values, {'stringagg': 'Foo1;Foo2;Foo3;Foo4'}) self.assertEqual(values, {'stringagg': 'Foo1;Foo2;Foo3;Foo4'})