CVE-2026-116566: Hostname Allowlist Bypass in CPython

Technical Reviewer
Updated: October 30th, 2026
6 mins read
CVE-2026-116566: Hostname Allowlist Bypass in CPython

Product Name: CPython (Python standard library)

Vulnerability: Hostname allowlist bypass via embedded NUL byte in socket.getaddrinfo()

Affected Versions: CPython versions earlier than 3.16.0 are affected by this vulnerability.

Fixed Version: 3.16.0 (first version outside the affected range; not yet released at time of writing).

CWE: CWE-158: Improper Handling of NUL Byte

CVE: CVE-2026-116566

Status: Patch merged upstream; awaiting release in CPython 3.16.0.

A security researcher at Astra on 28/10/2026 identified a hostname-validation flaw in CPython that could enable hostname-allowlist bypass in apps relying on the standard library’s socket module for both validation and connection.

The root cause is an improper NUL-byte handling issue (CWE-158) in the socket.getaddrinfo() implementation. The _socket_getaddrinfo_impl path accepts a hostname containing an embedded NUL byte and passes it to the C-level operating-system resolver, which may interpret the NUL as a C-string terminator and resolve only the prefix before it. The sibling API socket.gethostbyname() already rejects the same input with a TypeError, which is where the inconsistency becomes a real security problem.

This produces a hostname allowlist bypass, in which an application that validates the full hostname string against a policy and then connects via getaddrinfo()-based clients (urllib, http.client, asyncio, and most TLS clients downstream of them) can be steered into resolving a different host than the validator approved, with downstream SSRF-adjacent and policy-enforcement consequences depending on the application’s connection flow.

Technical Breakdown of CVE-2026-116566

CVE-2026-116566 was identified during a review of hostname-validation behavior across the CPython socket module APIs. The flaw sits at the boundary between Python-level validation and the C-level resolver call, in the way getaddrinfo() passes the host string into getaddrinfo(3) without sanitizing NUL bytes.

Consider a hostname of the form:

127.0.0.1\x00.allowed.example

An application performing a suffix-based allowlist check on the string sees .allowed.example and admits the input. The resolver, when invoked through socket.getaddrinfo(), treats the NUL byte as a C-string terminator and resolves 127.0.0.1. The validator and the resolver disagree on what the hostname is, which is the class of bug that allowlist bypasses live in.

The exact resolver behavior depends on the platform. Reported testing confirmed the inconsistency on Windows and on Linux systems using glibc.

How was CVE-2026-116566 discovered?

The behavior was found by comparing the input-validation posture of socket.getaddrinfo() against the sibling API socket.gethostbyname(). The latter already rejects NUL bytes in its argument, which raised the question of whether the former does the same. It does not.

The minimal differential test that confirmed the inconsistency:

import socket

host = "127.0.0.1\x00.allowed.example"

try:

    result = socket.getaddrinfo(host, 21, type=socket.SOCK_STREAM)

    print("getaddrinfo result:", result[0][4][0])

except Exception as exc:

    print("getaddrinfo rejected input:", repr(exc))

try:

    socket.gethostbyname(host)

    print("gethostbyname accepted input")

except Exception as exc:

    print("gethostbyname rejected input:", repr(exc))

In the reported tests, getaddrinfo() resolved the example to the prefix address (127.0.0.1), while gethostbyname() rejected the embedded NUL. Reproduction was reported on Python 3.11.9, 3.12.10, 3.13.12, 3.13.17, and 3.14.9, and the development branch was inspected at the source level.

How to replicate CVE-2026-116566

Prerequisites

  • A local Python environment running any version in the affected range (earlier than 3.16.0).
  • A controlled test host, since the proof-of-concept triggers a real resolver call.

Steps

  1. In a clean Python shell, import the socket module.
  2. Construct a hostname containing an embedded NUL byte, with the real target before the NUL and a decoy allowlisted suffix after it, for example "127.0.0.1\x00.allowed.example".
  3. Call socket.getaddrinfo(host, 21, type=socket.SOCK_STREAM) and inspect the resolved address in the result tuple.
  4. Call socket.gethostbyname(host) with the same input and observe the raised TypeError.
  5. Confirm that the two APIs disagree on whether the input is a valid hostname, which is the differential that produces the bypass in downstream applications.

The reported outcome is that getaddrinfo() returns an address for 127.0.0.1, while gethostbyname() refuses the call outright.

Impact of CVE-2026-116566

The practical exposure sits in applications that accept attacker-controlled URLs or hostnames, parse out the host component, validate it against an allowlist or denylist, and then make a network connection using a standard-library client that resolves via getaddrinfo() (which is the default path for most high-level networking in Python, including urllib, http.client, requests on the socket layer, asyncio network calls, and most TLS clients).

Where that pattern exists, CVE-2026-116566 can produce:

  • Hostname allowlist bypass, in which the string passes the policy check while the connection reaches a different host than the policy intended.
  • SSRF-adjacent exposure, where an application designed to connect only to permitted external hosts can be steered into resolving an internal-range address embedded before the NUL byte.
  • Suffix-check and TLS-SNI mismatch, in which the validator, the resolver, and the TLS layer disagree about the destination hostname, which can produce certificate-pinning and policy-enforcement gaps depending on the client’s behavior.

CVE-2026-116566 is not a universal remote-code-execution issue. Exploitability requires an affected Python runtime and an application flow in which the hostname validation path and the resolver path can be made to disagree on the input. The severity in a given deployment is a function of what the application connects to, with what credentials, and under which network policy.

Current Status of CVE-2026-116566

The issue was reported to CPython maintainers, and the fix has been merged upstream through a maintainer-created pull request titled “gh-1000000: Reject null bytes in getaddrinfo() host and port”, which brings the getaddrinfo() input-validation posture in line with gethostbyname(). CVE-2026-116566 is in the Reserved state with CWE-158 and a Moderate severity label on the GitHub Security Advisory.

The patch will ship in CPython 3.16.0, which is the first version outside the affected range. 3.16.0 has not been released yet at the time of writing, so every currently released CPython version remains affected until the fixed branch is tagged. Backports to the actively maintained branches (3.12, 3.13, 3.14, 3.15) may follow depending on the maintainers’ call.

What Can You Do?

Users running affected CPython versions are advised to upgrade to CPython 3.16.0 as soon as it ships, and to track any backport releases on the actively maintained branches in the interim. Until a patched runtime is available, the following mitigations reduce exposure in applications that perform hostname validation:

  • Reject NUL bytes in hostname input before validation. A one-line check ("\x00" in host) at the application boundary closes the differential before either standard-library API is called.
  • Validate the final normalized destination used for the connection, so that the string the resolver actually used matches the string the policy approved.
  • Avoid suffix-only allowlist checks. Combine them with exact-match or domain-tree logic that is not fooled by embedded control bytes.
  • Prefer URL-parsing libraries that normalize or reject control characters rather than hand-rolled hostname extraction.
  • Audit any call site that mixes urllib, http.client, socket, or asyncio network calls with a prior hostname-validation step, since those are the paths most likely to exhibit the differential.

Astra Security’s manual pentest covers input-validation differentials of this class, including hostname-parsing and SSRF-adjacent flows, during authenticated and unauthenticated testing.