VYPR
High severityNVD Advisory· Published Apr 29, 2021· Updated Aug 4, 2024

Denial of Service vulnerability in django-filter

CVE-2020-15225

Description

django-filter is a generic system for filtering Django QuerySets based on user selections. In django-filter before version 2.4.0, automatically generated NumberFilter instances, whose value was later converted to an integer, were subject to potential DoS from maliciously input using exponential format with sufficiently large exponents. Version 2.4.0+ applies a MaxValueValidator with a a default limit_value of 1e50 to the form field used by NumberFilter instances. In addition, NumberFilter implements the new get_max_validator() which should return a configured validator instance to customise the limit, or else None to disable the additional validation. Users may manually apply an equivalent validator if they are not able to upgrade.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
django-filterPyPI
< 2.4.02.4.0

Affected products

1

Patches

1
340cf7a23a2b

Version 2.4 (#1272)

https://github.com/carltongibson/django-filterCarlton GibsonSep 27, 2020via ghsa
9 files changed · +68 33
  • .bumpversion.cfg+0 24 removed
    @@ -1,24 +0,0 @@
    -[bumpversion]
    -current_version = 2.3.0
    -commit = False
    -tag = False
    -parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\.(?P<release>[a-z]+)(?P<num>\d+))?
    -serialize =
    -	{major}.{minor}.{patch}.{release}{num}
    -	{major}.{minor}.{patch}
    -
    -[bumpversion:file:django_filters/__init__.py]
    -
    -[bumpversion:file:setup.py]
    -
    -[bumpversion:file:docs/conf.py]
    -
    -[bumpversion:part:release]
    -optional_value = final
    -values =
    -	dev
    -	final
    -
    -[bumpversion:part:num]
    -first_value = 1
    -
    
  • CHANGES.rst+17 0 modified
    @@ -1,3 +1,20 @@
    +Version 2.4.0 (2020-9-27)
    +--------------------------
    +
    +* SECURITY: Added a ``MaxValueValidator`` to the form field for
    +  ``NumberFilter``. This prevents a potential DoS attack if numbers with very
    +  large exponents were subsequently converted to integers.
    +
    +  The default limit value for the validator is ``1e50``.
    +
    +  The new ``NumberFilter.get_max_validator()`` allows customising the used
    +  validator, and may return ``None`` to disable the validation entirely.
    +
    +* Added testing against Django 3.1 and Python 3.9.
    +
    +  In addition tests against Django main development branch are now required to
    +  pass.
    +
     Version 2.3.0 (2020-6-5)
     ------------------------
     
    
  • django_filters/filters.py+18 0 modified
    @@ -2,6 +2,7 @@
     from datetime import timedelta
     
     from django import forms
    +from django.core.validators import MaxValueValidator
     from django.db.models import Q
     from django.db.models.constants import LOOKUP_SEP
     from django.forms.utils import pretty_name
    @@ -357,6 +358,23 @@ class ModelMultipleChoiceFilter(QuerySetRequestMixin, MultipleChoiceFilter):
     class NumberFilter(Filter):
         field_class = forms.DecimalField
     
    +    def get_max_validator(self):
    +        """
    +        Return a MaxValueValidator for the field, or None to disable.
    +        """
    +        return MaxValueValidator(1e50)
    +
    +    @property
    +    def field(self):
    +        if not hasattr(self, '_field'):
    +            field = super().field
    +            max_validator = self.get_max_validator()
    +            if max_validator:
    +                field.validators.append(max_validator)
    +
    +            self._field = field
    +        return self._field
    +
     
     class NumericRangeFilter(Filter):
         field_class = RangeField
    
  • django_filters/__init__.py+1 1 modified
    @@ -10,7 +10,7 @@
         from . import rest_framework
     del pkgutil
     
    -__version__ = '2.3.0'
    +__version__ = '2.4.0'
     
     
     def parse_version(version):
    
  • docs/conf.py+5 3 modified
    @@ -13,6 +13,8 @@
     
     import sys, os
     
    +from django_filters import __version__
    +
     # If extensions (or modules to document with autodoc) are in another directory,
     # add these directories to sys.path here. If the directory is relative to the
     # documentation root, use os.path.abspath to make it absolute, like shown here.
    @@ -41,16 +43,16 @@
     
     # General information about the project.
     project = u'django-filter'
    -copyright = u'2019, Alex Gaynor, Carlton Gibson and others.'
    +copyright = u'2020, Alex Gaynor, Carlton Gibson and others.'
     
     # The version info for the project you're documenting, acts as replacement for
     # |version| and |release|, also used in various other places throughout the
     # built documents.
     #
     # The short X.Y version.
    -version = '2.3'
    +version = __version__
     # The full version, including alpha/beta/rc tags.
    -release = '2.3.0'
    +release = __version__
     
     # The language for content autogenerated by Sphinx. Refer to documentation
     # for a list of supported languages.
    
  • docs/ref/filters.txt+6 0 modified
    @@ -426,6 +426,12 @@ QuerySet, which then gets used as the model's manager::
     Filters based on a numerical value, used with ``IntegerField``, ``FloatField``,
     and ``DecimalField`` by default.
     
    +.. method:: NumberFilter.get_max_validator()
    +
    +    Return a ``MaxValueValidator`` instance that will be added to
    +    ``field.validators``. By default uses a limit value of ``1e50``. Return
    +    ``None`` to disable maximum value validation.
    +
     ``NumericRangeFilter``
     ~~~~~~~~~~~~~~~~~~~~~~
     
    
  • requirements/maintainer.txt+0 1 modified
    @@ -2,7 +2,6 @@ alabaster==0.7.7
     argh==0.26.1
     Babel==2.2.0
     backports.ssl-match-hostname==3.4.0.2
    -bumpversion==0.5.3
     certifi==2015.9.6.2
     docutils==0.12
     funcsigs==0.4
    
  • setup.py+7 4 modified
    @@ -2,12 +2,15 @@
     import sys
     from setuptools import setup, find_packages
     
    +# FIXME: Main module requires django to be present, so cannot run setup.py in
    +# clean environment.
    +# from django_filters import __version__
    +__version__ = '2.4.0'
    +
     f = open('README.rst')
     readme = f.read()
     f.close()
     
    -version = '2.3.0'
    -
     if sys.argv[-1] == 'publish':
         if os.system("pip freeze | grep wheel"):
             print("wheel not installed.\nUse `pip install wheel`.\nExiting.")
    @@ -18,13 +21,13 @@
         os.system("python setup.py sdist bdist_wheel")
         os.system("twine upload dist/*")
         print("You probably want to also tag the version now:")
    -    print("  git tag -a %s -m 'version %s'" % (version, version))
    +    print("  git tag -a %s -m 'version %s'" % (__version__, __version__))
         print("  git push --tags")
         sys.exit()
     
     setup(
         name='django-filter',
    -    version=version,
    +    version=__version__,
         description=('Django-filter is a reusable Django application for allowing'
                      ' users to filter querysets dynamically.'),
         long_description=readme,
    
  • tests/test_forms.py+14 0 modified
    @@ -255,3 +255,17 @@ def test_is_bound_and_not_valid(self):
             self.assertFalse(f.is_valid())
             self.assertEqual(f.data, {'price': 'four dollars'})
             self.assertEqual(f.errors, {'price': ['Enter a number.']})
    +
    +    def test_number_filter_max_value_validation(self):
    +        class F(FilterSet):
    +            class Meta:
    +                model = Book
    +                fields = ['average_rating']
    +
    +        f = F({'average_rating': '1E1001'})
    +        self.assertTrue(f.is_bound)
    +        self.assertFalse(f.is_valid())
    +        self.assertEqual(
    +            f.errors,
    +            {'average_rating': ['Ensure this value is less than or equal to 1e+50.']}
    +        )
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

16

News mentions

0

No linked articles in our index yet.