Python 3.14.8 closes a gap in TLS hostname validation
A TLS context could request hostname checking while wrap_bio silently lacked a hostname to check. Python 3.14.8 rejects that configuration and aligns related asyncio validation.
A TLS connection could complete certificate-chain verification without checking the peer's identity, even though the Python context had hostname checking enabled. Python 3.14.8, the expedited security release published on September 30, fixes that mismatch in SSLContext.wrap_bio(). The release identifies the issue as CVE-2026-19553.
The versioned changelog describes the missing input. When check_hostname was enabled but the caller supplied no server_hostname, the method could complete a handshake that verified the chain without verifying the identity. There was no indication that the hostname check had been skipped. The corrected implementation raises ValueError for that configuration.
This is exactly the kind of library contract that matters to my view of Python. Its ecosystem often supplies the complex implementation that makes choosing the language worthwhile. A setting that requests a security property must either enforce that property or reject a configuration that makes enforcement impossible. Successful completion otherwise gives the caller misleading evidence.
The context needs an identity to match
The ssl documentation for this release distinguishes hostname checking from the context's certificate-verification mode. The hostname check matches the peer certificate against a name. Certificate-chain verification supplies a different condition. Accepting the chain does not supply the missing hostname argument.
The interface therefore needs agreement between its configuration and its invocation. Enabling check_hostname expresses the desired check. Passing server_hostname identifies the name against which to perform it. Without that input, the implementation cannot carry out the requested comparison.
The distinction is visible in the documented coupling of settings. Enabling hostname checking also moves certificate verification from CERT_NONE to CERT_REQUIRED, and verification cannot return to CERT_NONE while hostname checking remains enabled. Python already treats these settings as a coherent policy. The missing-argument correction extends that consistency to the information supplied when constructing the connection.
The normal socket wrapper already validated this combination. Python 3.14.8 makes the BIO wrapper validate server_side, server_hostname, and session similarly to wrap_socket(). That consistency is important because changing the I/O integration method should not silently weaken the meaning of the same TLS context settings.
An application using a lower-level interface takes responsibility for more of the surrounding transport, but that does not imply it intended to disable a context's enabled checks. Rejecting the contradictory call makes that responsibility explicit at the point where the missing information can still be corrected.
BIO integration separates TLS from socket handling
The wrap_bio documentation says the method wraps incoming and outgoing BIO objects and returns an SSL object. TLS routines consume data through the incoming BIO and produce data through the outgoing one. The interface supports a transport integration different from wrapping a socket directly.
The hostname still belongs in the TLS operation. In this example, example.com is the intended peer identity, not a value discovered from whatever certificate arrives.
import ssl
context = ssl.create_default_context()
incoming = ssl.MemoryBIO()
outgoing = ssl.MemoryBIO()
connection = context.wrap_bio(
incoming, outgoing, server_hostname="example.com"
)
This creates the SSL object and establishes the input needed for identity checking. It is not a complete network client or a completed handshake. The caller still supplies and consumes transport data. Keeping that distinction visible prevents a short example from implying that construction itself authenticates a remote system.
The release also applies hostname validation in asyncio. Its loop.start_tls() and loop.create_connection() now validate the argument when passed an SSL context with check_hostname enabled. This addresses the same incomplete configuration through interfaces that applications may use without calling wrap_bio() themselves.
Rejection changes the application failure point
For affected callers, the patch can turn a formerly accepted call into an immediate exception. The correct interpretation is that the application had not supplied enough information for its requested identity check. Supplying the intended hostname resolves that missing input. Turning off checking changes the security policy and does not preserve the original request.
The default-context documentation supports using ssl.create_default_context() for settings appropriate to the intended purpose. That convenience cannot infer the peer identity for a separately constructed BIO connection. The application still knows which service it intended to contact and must convey that information to the TLS API.
There is another SSL correction in the same release, CVE-2026-19445, involving server-side context lifetime when an SNI callback switches contexts. The changelog explicitly says the usual server pattern that keeps the callback's context alive was not affected. That is a separate ownership defect, and it should not be confused with the missing-hostname validation issue.
My preference is for an interface that fails when a required security input is absent. That makes the error local to the call and preserves the meaning of the enabled setting. Python 3.14.8 establishes that behavior for BIO-based connections and corresponding asyncio paths. A caller requesting hostname validation must now provide the name needed to perform it.