CVE-2024-4032 (Other, published 2024-06-17T15:15Z)
Description: value: The “ipaddress” module contained incorrect information about whether certain IPv4 and IPv6 addresses were designated as “globally reachable” or “private”. This affected the is_private and is_global properties of the ipaddress.IPv4Address, ipaddress.IPv4Network, ipaddress.IPv6Address, and ipaddress.IPv6Network classes, where values wouldn’t be returned in accordance with the latest information from the IANA Special-Purpose Address Registries.

CPython 3.12.4 and 3.13.0a6 contain updated information from these registries and thus have the intended behavior.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/python/cpython
Files changed:
Doc/library/ipaddress.rst
Doc/whatsnew/3.13.rst
Lib/ipaddress.py
Lib/test/test_ipaddress.py
Misc/NEWS.d/next/Library/2024-03-14-01-38-44.gh-issue-113171.VFnObz.rst
Commit message: GH-113171: Fix "private" (non-global) IP address ranges (GH-113179)

* GH-113171: Fix "private" (really non-global) IP address ranges

The _private_networks variables, used by various is_private
implementations, were missing some ranges and at the same time had
overly strict ranges (where there are more specific ranges considered
globally reachable by the IANA registries).

This patch updates the ranges with what was missing or otherwise
incorrect.

I left 100.64.0.0/10 alone, for now, as it's been made special in [1]
and I'm not sure if we want to undo that as I don't quite understand the
motivation behind it.

The _address_exclude_many() call returns 8 networks for IPv4, 121
networks for IPv6.

[1] https://github.com/python/cpython/issues/61602


Vulnerable code:
                   for priv_network in self._constants._private_networks)
        return any(self in net for net in self._constants._private_networks)
        IPv4Network('192.0.0.0/29'),
        return any(self in net for net in self._constants._private_networks)
        IPv6Network('2001:2::/48'),
        IPv6Network('2001:10::/28'),
        self.assertEqual(True, ipaddress.ip_network("2001::/23").is_private)

Fixed code:
      .. versionchanged:: 3.13

         Fixed some false positives and false negatives.

         * ``192.0.0.0/24`` is considered private with the exception of ``192.0.0.9/32`` and
           ``192.0.0.10/32`` (previously: only the ``192.0.0.0/29`` sub-range was considered private).
         * ``64:ff9b:1::/48`` is considered private.
         * ``2002::/16`` is considered private.
         * There are exceptions within ``2001::/23`` (otherwise considered private): ``2001:1::1/128``,
           ``2001:1::2/128``, ``2001:3::/32``, ``2001:4:112::/48``, ``2001:20::/28``, ``2001:30::/28``.
           The exceptions are not considered private.

      .. versionchanged:: 3.13

         Fixed some false positives and false negatives, see :attr:`is_private` for details.

* Fix ``is_global`` and ``is_private`` behavior in ``IPv4Address``, ``IPv6Address``, ``IPv4Network``
  and ``IPv6Network``.
                   for priv_network in self._constants._private_networks) and all(
                    self.network_address not in network and
                    self.broadcast_address not in network
                    for network in self._constants._private_networks_exceptions
                )
        return (
            any(self in net for net in self._constants._private_networks)
            and all(self not in net for net in self._constants._private_networks_exceptions)
        )
    # Not globally reachable address blocks listed on
    # https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
        IPv4Network('192.0.0.0/24'),
    _private_networks_exceptions = [
        IPv4Network('192.0.0.9/32'),
        IPv4Network('192.0.0.10/32'),
    ]

        return (
            any(self in net for net in self._constants._private_networks)
            and all(self not in net for net in self._constants._private_networks_exceptions)
        )
    # Not globally reachable address blocks listed on
    # https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
        IPv6Network('64:ff9b:1::/48'),
        # IANA says N/A, let's consider it not globally reachable to be safe
        IPv6Network('2002::/16'),
    _private_networks_exceptions = [
        IPv6Network('2001:1::1/128'),
        IPv6Network('2001:1::2/128'),
        IPv6Network('2001:3::/32'),
        IPv6Network('2001:4:112::/48'),
        IPv6Network('2001:20::/28'),
        IPv6Network('2001:30::/28'),
    ]

        self.assertFalse(ipaddress.ip_address('192.0.0.0').is_global)
        self.assertTrue(ipaddress.ip_address('192.0.0.9').is_global)
        self.assertTrue(ipaddress.ip_address('192.0.0.10').is_global)
        self.assertFalse(ipaddress.ip_address('192.0.0.255').is_global)
        self.assertEqual(False, ipaddress.ip_network("192.0.0.9/32").is_private)
        self.assertEqual(False, ipaddress.ip_network("2001:3::/48").is_private)
        self.assertFalse(ipaddress.ip_address('64:ff9b:1::').is_global)
        self.assertFalse(ipaddress.ip_address('2001::').is_global)
        self.assertTrue(ipaddress.ip_address('2001:1::1').is_global)
        self.assertTrue(ipaddress.ip_address('2001:1::2').is_global)
        self.assertFalse(ipaddress.ip_address('2001:2::').is_global)
        self.assertTrue(ipaddress.ip_address('2001:3::').is_global)
        self.assertFalse(ipaddress.ip_address('2001:4::').is_global)
        self.assertTrue(ipaddress.ip_address('2001:4:112::').is_global)
        self.assertFalse(ipaddress.ip_address('2001:10::').is_global)
        self.assertTrue(ipaddress.ip_address('2001:20::').is_global)
        self.assertTrue(ipaddress.ip_address('2001:30::').is_global)
        self.assertFalse(ipaddress.ip_address('2001:40::').is_global)
        self.assertFalse(ipaddress.ip_address('2002::').is_global)

Fixed various false positives and false negatives in

* :attr:`ipaddress.IPv4Address.is_private` (see these docs for details)
* :attr:`ipaddress.IPv4Address.is_global`
* :attr:`ipaddress.IPv6Address.is_private`
* :attr:`ipaddress.IPv6Address.is_global`

Also in the corresponding :class:`ipaddress.IPv4Network` and :class:`ipaddress.IPv6Network`
attributes.