CVE-2026-63374 Overview
AnyIO is a high-level asynchronous concurrency and networking framework that runs on top of either Trio or asyncio. Versions prior to 4.14.2 contain an improper certificate validation flaw [CWE-295] in connect_tcp() and TLSStream.wrap(). These functions validate internationalized host names after the Python standard library converts them using IDNA 2003 instead of IDNA 2008. The two encodings can produce different ASCII representations for the same Unicode label. An attacker who hijacks or redirects a connection to a non-ASCII domain can obtain a legitimate certificate for the alternate IDNA 2003 hostname and present it to the client, causing TLS validation to succeed against a malicious endpoint. The issue is fixed in AnyIO 4.14.2.
Critical Impact
Attackers can defeat TLS hostname verification for internationalized domains and impersonate legitimate services without triggering certificate errors.
Affected Products
- AnyIO versions prior to 4.14.2
- Python applications using anyio.connect_tcp() with TLS to internationalized domains
- Python applications using anyio.streams.tls.TLSStream.wrap() with internationalized host names
Discovery Timeline
- 2026-09-22 - CVE-2026-63374 published to NVD
- 2026-09-22 - Last updated in NVD database
Technical Details for CVE-2026-63374
Vulnerability Analysis
Internationalized Domain Names in Applications (IDNA) defines how Unicode labels convert to ASCII for DNS and TLS. IDNA 2003 and IDNA 2008 handle several characters differently, most notably the German sharp s (ß), the final sigma (ς), and ZWJ/ZWNJ code points. Python's built-in str.encode("idna") implements IDNA 2003, while the current standard for TLS hostname matching is IDNA 2008 with UTS-46 mapping.
AnyIO's TLS helpers relied on the standard library encoder before matching the host name against the peer certificate's Subject Alternative Names. A Unicode host name could therefore be converted to one ASCII label at connect time but a different ASCII label under the modern encoding used by certificate authorities and browsers.
Root Cause
The root cause is reliance on Python's IDNA 2003 implementation inside TLSStream.wrap() and connect_tcp(). When the host argument contained non-ASCII characters, AnyIO produced an ASCII label that did not match the label a compliant CA would issue for the same Unicode name, breaking the identity binding that TLS hostname verification depends on.
Attack Vector
The attack requires a network position capable of hijacking or redirecting traffic destined for a non-ASCII domain, for example through DNS spoofing, BGP hijack, or a compromised upstream resolver. The attacker registers or obtains the alternate ASCII domain produced by IDNA 2003, acquires a legitimate certificate for it from any public CA, and terminates the redirected TLS session. AnyIO's client validates the certificate against the IDNA 2003 label and accepts the malicious endpoint.
# Patch from src/anyio/_core/_sockets.py adding IDNA 2008 resolution
IPAddressFamily = Literal[AddressFamily.AF_INET, AddressFamily.AF_INET6]
def idna2008_resolve(host: str) -> bytes:
try:
return host.encode("ascii")
except UnicodeEncodeError:
import idna
return idna.encode(host, uts46=True)
# tls_hostname given
@overload
async def connect_tcp(
# Source: https://github.com/agronholm/anyio/commit/68f58915f82d9be8109ebbbd8f5d70577d43f2ce
The fix introduces idna2008_resolve(), which uses the third-party idna package with UTS-46 mapping whenever the host name contains non-ASCII characters, ensuring the label used for certificate matching aligns with modern CA issuance rules.
Detection Methods for CVE-2026-63374
Indicators of Compromise
- TLS connections from Python services to unexpected ASCII domains that are IDNA 2003 variants of legitimate internationalized names.
- Certificates in TLS session logs whose Subject Alternative Names differ from the intended Unicode host requested by the application.
- DNS resolution anomalies for internationalized domains, especially responses pointing to unfamiliar autonomous systems or hosting providers.
Detection Strategies
- Inventory Python environments and identify installed AnyIO versions below 4.14.2 using pip list or software composition analysis tooling.
- Instrument outbound TLS from application hosts to log the requested SNI and validated certificate identity, then alert on mismatches for internationalized domains.
- Search source repositories for calls to anyio.connect_tcp and TLSStream.wrap where the target host is user-controllable or contains Unicode characters.
Monitoring Recommendations
- Monitor DNS query and response pairs for punycode labels that appear to be lookalikes of business-critical internationalized domains.
- Correlate egress TLS metadata with expected destinations and flag connections established to newly registered ASCII domains resembling IDNA 2003 forms.
- Track dependency updates in CI/CD pipelines to confirm AnyIO 4.14.2 or later is enforced across builds.
How to Mitigate CVE-2026-63374
Immediate Actions Required
- Upgrade AnyIO to version 4.14.2 or later across every runtime and container image.
- Audit dependencies for transitive pins that hold AnyIO below 4.14.2 and update lockfiles accordingly.
- For applications connecting to internationalized domains, review recent TLS session logs for anomalies that could indicate exploitation attempts.
Patch Information
The fix is delivered in AnyIO Release 4.14.2 via commit 68f58915f82d9be8109ebbbd8f5d70577d43f2ce. The patch introduces idna2008_resolve() and routes host name encoding through the idna package with UTS-46 mapping. See the GitHub Security Advisory GHSA-82r6-8w77-94w6 and the GitHub Pull Request Discussion for the full analysis.
Workarounds
- Restrict outbound TLS from Python services to a curated allowlist of ASCII destinations, avoiding runtime resolution of Unicode host names.
- Pre-encode host names in application code with the idna package using idna.encode(host, uts46=True) before passing them to connect_tcp() or TLSStream.wrap().
- Pin certificate identities via mutual TLS or certificate pinning where feasible to prevent acceptance of arbitrary CA-issued certificates.
# Upgrade AnyIO to the fixed release
pip install --upgrade 'anyio>=4.14.2'
# Verify the installed version
python -c "import anyio; print(anyio.__version__)"
# Enforce the minimum version in requirements.txt
echo 'anyio>=4.14.2' >> requirements.txt
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.