Repository: pydantic/pydantic

Issue:
potential DOS risk with pydantic - fix pending
I have been made aware of a potential DOS attack risk in pydantic.

The fix I believe is relatively trivial, I will release:
* `v1.5.2` based of the current `v1.5.1` tag
* `v1.4.1` based of the current `v1.4` tag

These releases will be made just after **1pm UTC** on **2020/5/11**, that's next Monday.

If you require a fix to any other version, please let me know on this issue.


Discussion:
To wait for potential upstream fixes to this issue, these releases have been delayed.

I'll comment here as soon as I know when a fix can be released for pydantic.
Is this issue still necessary?
The python security team have not yet fixed the the upstream error (I don't really understand why) but have ask packages not to mitigate the problem in libraries to avoid making it public.

The whole situation is frustrating.
Hi Samuel, is the underlying vulnerability still present in the upstream such that the DOS risk survives in the current version of the library? If not, what version was the issue resolved in? Thank you.

Also, I believe we are _well_ into responsible disclosure territory with respect to the upstream, given the time period that has elapsed. 
Quick update on this since a few people have asked about it.

This an issue in cpython, it's not specific to pydantic. All versions of python are effected.

The python security list were informed about it back in 2020 but after a flurry of initial emails, progress on a fix stopped as far as I'm aware.

After @mruser's comment 2 weeks ago, I followed up with a few individuals involved and tried to press for a proper fix.

The last update was 2 days ago, that the issue was being discussed between some core devs. and the SC.

---

In short, while I'm disappointed this hasn't fixed sooner, I'm hopeful it will be fixed soon.

I was asked not to fix it in pydantic to avoid making the vulnerability public, I'll stick to that for another few months in the hope of an upstream fix.
Is the vulnerability somehow connected to the [well known issues with NaN implementation](https://blog.bitdiscovery.com/2021/12/python-nan-injection/)? If so, the issue should be closed, in my opinion.
No
Is this issue effecting all versions of Pydantic, on version 1.4 and beyond, or only on 1.4 and 1.5.1?
This has now been made public and it seems a fix will be out soon.

https://github.com/python/cpython/issues/95778

If you're parsing, JSON the simplest solution is to use ujson which doesn't suffer from this problem.

I'll see if I can get a fix it which limits input to ints soon. 

Resolving patch:
diff --git a/pydantic/validators.py b/pydantic/validators.py
--- a/pydantic/validators.py
+++ b/pydantic/validators.py
@@ -120,10 +120,23 @@ def bool_validator(v: Any) -> bool:
     raise errors.BoolError()
 
 
+# matches the default limit cpython, see https://github.com/python/cpython/pull/96500
+max_str_int = 4_300
+
+
 def int_validator(v: Any) -> int:
     if isinstance(v, int) and not (v is True or v is False):
         return v
 
+    # see https://github.com/pydantic/pydantic/issues/1477 and in turn, https://github.com/python/cpython/issues/95778
+    # this check should be unnecessary once patch releases are out for 3.7, 3.8, 3.9 and 3.10
+    # but better to check here until then.
+    # NOTICE: this does not fully protect user from the DOS risk since the standard library JSON implementation
+    # (and other std lib modules like xml) use `int()` and are likely called before this, the best workaround is to
+    # 1. update to the latest patch release of python once released, 2. use a different JSON library like ujson
+    if isinstance(v, (str, bytes, bytearray)) and len(v) > max_str_int:
+        raise errors.IntegerError()
+
     try:
         return int(v)
     except (TypeError, ValueError, OverflowError):


Test patch:
diff --git a/tests/test_edge_cases.py b/tests/test_edge_cases.py
--- a/tests/test_edge_cases.py
+++ b/tests/test_edge_cases.py
@@ -2038,3 +2038,38 @@ class Custom:
         __fields__ = True
 
     assert not issubclass(Custom, BaseModel)
+
+
+def test_long_int():
+    """
+    see https://github.com/pydantic/pydantic/issues/1477 and in turn, https://github.com/python/cpython/issues/95778
+    """
+
+    class Model(BaseModel):
+        x: int
+
+    assert Model(x='1' * 4_300).x == int('1' * 4_300)
+    assert Model(x=b'1' * 4_300).x == int('1' * 4_300)
+    assert Model(x=bytearray(b'1' * 4_300)).x == int('1' * 4_300)
+
+    too_long = '1' * 4_301
+    with pytest.raises(ValidationError) as exc_info:
+        Model(x=too_long)
+
+    assert exc_info.value.errors() == [
+        {
+            'loc': ('x',),
+            'msg': 'value is not a valid integer',
+            'type': 'type_error.integer',
+        },
+    ]
+
+    too_long_b = too_long.encode('utf-8')
+    with pytest.raises(ValidationError):
+        Model(x=too_long_b)
+    with pytest.raises(ValidationError):
+        Model(x=bytearray(too_long_b))
+
+    # this used to hang indefinitely
+    with pytest.raises(ValidationError):
+        Model(x='1' * (10**7))