gh-128840: Limit the number of parts in IPv6 address parsing (GH-128841)

GH-128840: Limit the number of parts in IPv6 address parsing
Limit length of IP address string to 39

---------

Co-authored-by: Hugo van Kemenade <1324225+hugovk@users.noreply.github.com>
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
This commit is contained in:
Seth Michael Larson 2025-05-23 21:57:13 -05:00 committed by GitHub
parent 973b8f69d3
commit 47f1161d3a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 2 deletions

View file

@ -1660,8 +1660,16 @@ class _BaseV6:
"""
if not ip_str:
raise AddressValueError('Address cannot be empty')
if len(ip_str) > 39:
msg = ("At most 39 characters expected in "
f"{ip_str[:14]!r}({len(ip_str)-28} chars elided){ip_str[-14:]!r}")
raise AddressValueError(msg)
parts = ip_str.split(':')
# We want to allow more parts than the max to be 'split'
# to preserve the correct error message when there are
# too many parts combined with '::'
_max_parts = cls._HEXTET_COUNT + 1
parts = ip_str.split(':', maxsplit=_max_parts)
# An IPv6 address needs at least 2 colons (3 parts).
_min_parts = 3
@ -1681,7 +1689,6 @@ class _BaseV6:
# An IPv6 address can't have more than 8 colons (9 parts).
# The extra colon comes from using the "::" notation for a single
# leading or trailing zero part.
_max_parts = cls._HEXTET_COUNT + 1
if len(parts) > _max_parts:
msg = "At most %d colons permitted in %r" % (_max_parts-1, ip_str)
raise AddressValueError(msg)

View file

@ -397,6 +397,17 @@ class AddressTestCase_v6(BaseTestCase, CommonTestMixin_v6):
# A trailing IPv4 address is two parts
assertBadSplit("10:9:8:7:6:5:4:3:42.42.42.42%scope")
def test_bad_address_split_v6_too_long(self):
def assertBadSplit(addr):
msg = r"At most 39 characters expected in %s"
with self.assertAddressError(msg, repr(re.escape(addr[:14]))):
ipaddress.IPv6Address(addr)
# Long IPv6 address
long_addr = ("0:" * 10000) + "0"
assertBadSplit(long_addr)
assertBadSplit(long_addr + "%zoneid")
def test_bad_address_split_v6_too_many_parts(self):
def assertBadSplit(addr):
msg = "Exactly 8 parts expected without '::' in %r"

View file

@ -0,0 +1,2 @@
Short-circuit the processing of long IPv6 addresses early in :mod:`ipaddress` to prevent excessive
memory consumption and a minor denial-of-service.