https://github.com/python/cpython/commit/131a3a66c5f400b588f9fd2732a5ed4e89623ee3
commit: 131a3a66c5f400b588f9fd2732a5ed4e89623ee3
branch: main
author: Seth Larson <[email protected]>
committer: StanFromIreland <[email protected]>
date: 2026-10-29T17:15:29Z
summary:

gh-160898: Reject null bytes in `socket.getaddrinfo()` host and port (#160899)

Co-authored-by: Stan Ulbrych <[email protected]>

files:
A Misc/NEWS.d/next/Security/2026-10-27-16-25-40.gh-issue-160898.epi53X.rst
M Doc/library/socket.rst
M Lib/test/test_socket.py
M Modules/socketmodule.c

diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
index 054ccc556740c2..5a1cd95da527ea 100644
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -1065,6 +1065,9 @@ The :mod:`!socket` module also offers various 
network-related services:
       for IPv6 multicast addresses, string representing an address will not
       contain ``%scope_id`` part.
 
+   .. versionchanged:: next
+      Null characters are now rejected in the *host* and *port* parameters.
+
 .. _Happy Eyeballs: https://en.wikipedia.org/wiki/Happy_Eyeballs
 
 .. function:: getfqdn([name])
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 51b666bbaba827..b37925af1e2d0f 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -2104,6 +2104,39 @@ def test_getnameinfo_ipv6_scopeid_numeric(self):
         nameinfo = socket.getnameinfo(sockaddr, socket.NI_NUMERICHOST | 
socket.NI_NUMERICSERV)
         self.assertEqual(nameinfo, ('ff02::1de:c0:face:8d%' + str(ifindex), 
'1234'))
 
+    def test_getaddrinfo_null_bytes(self):
+        # getaddrinfo() must reject embedded null bytes instead of silently
+        # truncating the host or port at the C boundary.  The checks run
+        # before any name resolution, so no network access is needed.
+        hosts = [
+            # embedded
+            'local\0host', b'local\0host',
+            # trailing
+            'localhost\0', b'localhost\0',
+            # leading (truncates to '')
+            '\0localhost', b'\0localhost',
+            '\0', b'\0',
+            # non-ASCII, goes through IDNA
+            'b\xfccher\0.example',
+        ]
+        for host in hosts:
+            with self.subTest(host=host):
+                with self.assertRaisesRegex(ValueError, 'host'):
+                    socket.getaddrinfo(host, 80)
+
+        ports = [
+            '8\x000',
+            b'8\x000',
+            'http\0',
+            b'http\0',
+            '\0',
+            b'\0'
+        ]
+        for port in ports:
+            with self.subTest(port=port):
+                with self.assertRaisesRegex(ValueError, 'port'):
+                    socket.getaddrinfo("localhost", port)
+
     def test_str_for_enums(self):
         # Make sure that the AF_* and SOCK_* constants have enum-like string
         # reprs.
diff --git 
a/Misc/NEWS.d/next/Security/2026-10-27-16-25-40.gh-issue-160898.epi53X.rst 
b/Misc/NEWS.d/next/Security/2026-10-27-16-25-40.gh-issue-160898.epi53X.rst
new file mode 100644
index 00000000000000..2eb04454cbd9a7
--- /dev/null
+++ b/Misc/NEWS.d/next/Security/2026-10-27-16-25-40.gh-issue-160898.epi53X.rst
@@ -0,0 +1,4 @@
+.. cve: CVE-2026-116566
+
+:func:`socket.getaddrinfo` now rejects null bytes within *host* and *port*
+parameters as this previously caused the values to be silently truncated.
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 97146b1d752c3d..4df03284cbdd24 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -7018,6 +7018,7 @@ _socket_getaddrinfo_impl(PyObject *module, PyObject 
*hobj, PyObject *pobj,
     struct addrinfo *res0 = NULL;
     PyObject *pstr = NULL;
     const char *hptr, *pptr;
+    Py_ssize_t hlen = 0, plen = 0;
     int error;
     PyObject *all = (PyObject *)NULL;
     PyObject *idna = NULL;
@@ -7030,13 +7031,20 @@ _socket_getaddrinfo_impl(PyObject *module, PyObject 
*hobj, PyObject *pobj,
             return NULL;
         assert(PyBytes_Check(idna));
         hptr = PyBytes_AS_STRING(idna);
+        hlen = PyBytes_GET_SIZE(idna);
     } else if (PyBytes_Check(hobj)) {
-        hptr = PyBytes_AsString(hobj);
+        hptr = PyBytes_AS_STRING(hobj);
+        hlen = PyBytes_GET_SIZE(hobj);
     } else {
         PyErr_SetString(PyExc_TypeError,
                         "getaddrinfo() argument 1 must be string or None");
         return NULL;
     }
+    if (hptr != NULL && strlen(hptr) != (size_t)hlen) {
+        PyErr_SetString(PyExc_ValueError,
+                        "getaddrinfo() host must not contain null characters");
+        goto err;
+    }
     if (PyIndex_Check(pobj)) {
         pstr = PyNumber_Index(pobj);
         if (pstr == NULL)
@@ -7046,21 +7054,27 @@ _socket_getaddrinfo_impl(PyObject *module, PyObject 
*hobj, PyObject *pobj,
         if (pstr == NULL)
             goto err;
         assert(PyUnicode_Check(pstr));
-        pptr = PyUnicode_AsUTF8(pstr);
+        pptr = PyUnicode_AsUTF8AndSize(pstr, &plen);
         if (pptr == NULL)
             goto err;
     } else if (PyUnicode_Check(pobj)) {
-        pptr = PyUnicode_AsUTF8(pobj);
+        pptr = PyUnicode_AsUTF8AndSize(pobj, &plen);
         if (pptr == NULL)
             goto err;
     } else if (PyBytes_Check(pobj)) {
         pptr = PyBytes_AS_STRING(pobj);
+        plen = PyBytes_GET_SIZE(pobj);
     } else if (pobj == Py_None) {
         pptr = (char *)NULL;
     } else {
         PyErr_SetString(PyExc_OSError, "Int or String expected");
         goto err;
     }
+    if (pptr != NULL && strlen(pptr) != (size_t)plen) {
+        PyErr_SetString(PyExc_ValueError,
+                        "getaddrinfo() port must not contain null characters");
+        goto err;
+    }
 #if defined(__APPLE__) && defined(AI_NUMERICSERV)
     if ((flags & AI_NUMERICSERV) && (pptr == NULL || (pptr[0] == '0' && 
pptr[1] == 0))) {
         /* On OSX up to at least OSX 10.8 getaddrinfo crashes

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to