CVE-2021-29510 (Python, published 2021-05-13T19:15Z)
Description: value: Pydantic is a data validation and settings management using Python type hinting. In affected versions passing either `'infinity'`, `'inf'` or `float('inf')` (or their negatives) to `datetime` or `date` fields causes validation to run forever with 100% CPU usage (on one CPU). Pydantic has been patched with fixes available in the following versions: v1.8.2, v1.7.4, v1.6.2. All these versions are available on pypi(https://pypi.org/project/pydantic/#history), and will be available on conda-forge(https://anaconda.org/conda-forge/pydantic) soon. See the changelog(https://pydantic-docs.helpmanual.io/) for details. If you absolutely can't upgrade, you can work around this risk using a validator(https://pydantic-docs.helpmanual.io/usage/validators/) to catch these values. This is not an ideal solution (in particular you'll need a slightly different function for datetimes), instead of a hack like this you should upgrade pydantic. If you are not using v1.8.x, v1.7.x or v1.6.x and are unable to upgrade to a fixed version of pydantic, please create an issue at https://github.com/samuelcolvin/pydantic/issues requesting a back-port, and we will endeavour to release a patch for earlier versions of pydantic.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-835 \u2014 Loop with Unreachable Exit Condition ('Infinite Loop')
The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.
Repository: https://github.com/samuelcolvin/pydantic
Files changed:
changes/2776-samuelcolvin.md
pydantic/datetime_parse.py
tests/test_datetime_parse.py
Commit message: Merge pull request from GHSA-5jqp-qgf6-3pvh

* fix infinite loop in datetime parsing

* add change description

* switch to set a max datetime number

Vulnerable code:
    if result == errors.DateError:
        with pytest.raises(errors.DateError):
    if result == errors.DateTimeError:
        with pytest.raises(errors.DateTimeError):

Fixed code:
**Security fix:** Fix `date` and `datetime` parsing so passing either `'infinity'` or `float('inf')` 
(or their negative values) does not cause an infinite loop.
# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9
MAX_NUMBER = int(3e20)
    if seconds > MAX_NUMBER:
        return datetime.max
    elif seconds < -MAX_NUMBER:
        return datetime.min

        ('infinity', date(9999, 12, 31)),
        ('inf', date(9999, 12, 31)),
        (float('inf'), date(9999, 12, 31)),
        ('infinity ', date(9999, 12, 31)),
        (int('1' + '0' * 100), date(9999, 12, 31)),
        (1e1000, date(9999, 12, 31)),
        ('-infinity', date(1, 1, 1)),
        ('-inf', date(1, 1, 1)),
        ('nan', ValueError),
    if type(result) == type and issubclass(result, Exception):
        with pytest.raises(result):
        ('infinity', datetime(9999, 12, 31, 23, 59, 59, 999999)),
        ('inf', datetime(9999, 12, 31, 23, 59, 59, 999999)),
        ('inf ', datetime(9999, 12, 31, 23, 59, 59, 999999)),
        (1e50, datetime(9999, 12, 31, 23, 59, 59, 999999)),
        (float('inf'), datetime(9999, 12, 31, 23, 59, 59, 999999)),
        ('-infinity', datetime(1, 1, 1, 0, 0)),
        ('-inf', datetime(1, 1, 1, 0, 0)),
        ('nan', ValueError),
    if type(result) == type and issubclass(result, Exception):
        with pytest.raises(result):


def test_nan():
    class Model(BaseModel):
        dt: datetime
        d: date

    with pytest.raises(ValidationError) as exc_info:
        Model(dt='nan', d='nan')
    assert exc_info.value.errors() == [
        {
            'loc': ('dt',),
            'msg': 'cannot convert float NaN to integer',
            'type': 'value_error',
        },
        {
            'loc': ('d',),
            'msg': 'cannot convert float NaN to integer',
            'type': 'value_error',
        },
    ]