CVE-2020-15225 (Python, published 2021-04-29T21:15Z)
Description: value: 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.
Severity: MEDIUM (CVSS v3 base score: 6.5)
Weakness: CWE-681 \u2014 Incorrect Conversion between Numeric Types
When converting from one data type to another, such as long to integer, data can be omitted or translated in a way that produces unexpected values. If the resulting values are used in a sensitive context, then dangerous behaviors may occur.
Repository: https://github.com/carltongibson/django-filter
Files changed:
CHANGES.rst
django_filters/__init__.py
django_filters/filters.py
docs/conf.py
docs/ref/filters.txt
requirements/maintainer.txt
setup.py
tests/test_forms.py
Commit message: Version 2.4 (#1272)

* Added MaxValueValidator to NumberFilter.
* Update docs copyright year.
* Droped using bumpversion.


Vulnerable code:
[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

__version__ = '2.3.0'
copyright = u'2019, Alex Gaynor, Carlton Gibson and others.'
version = '2.3'
release = '2.3.0'
bumpversion==0.5.3
version = '2.3.0'

    print("  git tag -a %s -m 'version %s'" % (version, version))
    version=version,

Fixed code:
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.4.0'
from django.core.validators import MaxValueValidator
    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

from django_filters import __version__

copyright = u'2020, Alex Gaynor, Carlton Gibson and others.'
version = __version__
release = __version__
.. 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.

# 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'

    print("  git tag -a %s -m 'version %s'" % (__version__, __version__))
    version=__version__,

    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.']}
        )