[4.0.x] Fixed CVE-2021-45116 -- Fixed potential information disclosure in dictsort template filter.

Thanks to Dennis Brinkrolf for the report.

Co-authored-by: Adam Johnson <me@adamj.eu>
This commit is contained in:
Florian Apolloner 2021-12-27 14:53:18 +01:00 committed by Carlton Gibson
parent df79ef03ac
commit 2a8ec7f546
7 changed files with 135 additions and 7 deletions

View file

@ -1,9 +1,58 @@
from django.template.defaultfilters import dictsort
from django.template.defaultfilters import _property_resolver, dictsort
from django.test import SimpleTestCase
class User:
password = 'abc'
_private = 'private'
@property
def test_property(self):
return 'cde'
def test_method(self):
"""This is just a test method."""
class FunctionTests(SimpleTestCase):
def test_property_resolver(self):
user = User()
dict_data = {'a': {
'b1': {'c': 'result1'},
'b2': user,
'b3': {'0': 'result2'},
'b4': [0, 1, 2],
}}
list_data = ['a', 'b', 'c']
tests = [
('a.b1.c', dict_data, 'result1'),
('a.b2.password', dict_data, 'abc'),
('a.b2.test_property', dict_data, 'cde'),
# The method should not get called.
('a.b2.test_method', dict_data, user.test_method),
('a.b3.0', dict_data, 'result2'),
(0, list_data, 'a'),
]
for arg, data, expected_value in tests:
with self.subTest(arg=arg):
self.assertEqual(_property_resolver(arg)(data), expected_value)
# Invalid lookups.
fail_tests = [
('a.b1.d', dict_data, AttributeError),
('a.b2.password.0', dict_data, AttributeError),
('a.b2._private', dict_data, AttributeError),
('a.b4.0', dict_data, AttributeError),
('a', list_data, AttributeError),
('0', list_data, TypeError),
(4, list_data, IndexError),
]
for arg, data, expected_exception in fail_tests:
with self.subTest(arg=arg):
with self.assertRaises(expected_exception):
_property_resolver(arg)(data)
def test_sort(self):
sorted_dicts = dictsort(
[{'age': 23, 'name': 'Barbara-Ann'},
@ -21,7 +70,7 @@ class FunctionTests(SimpleTestCase):
def test_dictsort_complex_sorting_key(self):
"""
Since dictsort uses template.Variable under the hood, it can sort
Since dictsort uses dict.get()/getattr() under the hood, it can sort
on keys like 'foo.bar'.
"""
data = [
@ -60,3 +109,9 @@ class FunctionTests(SimpleTestCase):
self.assertEqual(dictsort('Hello!', 'age'), '')
self.assertEqual(dictsort({'a': 1}, 'age'), '')
self.assertEqual(dictsort(1, 'age'), '')
def test_invalid_args(self):
"""Fail silently if invalid lookups are passed."""
self.assertEqual(dictsort([{}], '._private'), '')
self.assertEqual(dictsort([{'_private': 'test'}], '_private'), '')
self.assertEqual(dictsort([{'nested': {'_private': 'test'}}], 'nested._private'), '')

View file

@ -46,3 +46,9 @@ class FunctionTests(SimpleTestCase):
self.assertEqual(dictsortreversed('Hello!', 'age'), '')
self.assertEqual(dictsortreversed({'a': 1}, 'age'), '')
self.assertEqual(dictsortreversed(1, 'age'), '')
def test_invalid_args(self):
"""Fail silently if invalid lookups are passed."""
self.assertEqual(dictsortreversed([{}], '._private'), '')
self.assertEqual(dictsortreversed([{'_private': 'test'}], '_private'), '')
self.assertEqual(dictsortreversed([{'nested': {'_private': 'test'}}], 'nested._private'), '')