The bouncer checks IDs at the VIP door, but a garbled name makes him wave you through the main entrance instead
CVE-2026-75595 is an authentication bypass in Netty's SslClientHelloHandler#decode. An off-by-five-byte bounds-check error means the code validates 4 bytes of buffer space but then reads 9 (5-byte TLS record header + 4-byte handshake header). When an attacker sends a crafted ClientHello whose handshake header spans TLS records — with a first-record payload of only 1–3 bytes — the read triggers an IndexOutOfBoundsException. The exception handler calls select(ctx, null), which silently routes the connection to the default SslContext instead of the SNI-specific one. In deployments where the SNI-specific context enforces clientAuth=REQUIRE but the default context uses clientAuth=NONE or OPTIONAL, this converts a parsing error into a full mTLS bypass. Affected versions: all Netty prior to 4.1.137.Final and 4.2.0.Final through 4.2.16.Final.
Third-party scanners auto-labeled this CRITICAL at CVSS 9.1, but the GitHub advisory from the Netty project itself rates it High. The Netty project's rating is closer to reality. The CVSS vector uses AC:L (low attack complexity), which is misleading — the chain only fires when three simultaneous configuration conditions are met: SNI-based mTLS routing is in use, the default SslContext is more permissive than the SNI-specific one, and there is no application-layer certificate verification. Most Netty deployments use a single SslContext and never touch SslClientHelloHandler at all. Adjusting for real-world attack complexity (AC:H) yields CVSS 7.4, which better reflects the conditional nature of this bug.
4 steps from start to impact.
Identify a Netty service using SNI-based TLS routing
SslClientHelloHandler for SNI-based context selection — typically an API gateway, multi-tenant TLS termination proxy, or service mesh ingress. Scanning for server banners is unreliable since Netty doesn't advertise itself, but TLS fingerprinting (JA3/JA4 hashes) can narrow the field. The attacker tests multiple SNI values to confirm the server differentiates behavior by hostname.- Target runs Netty < 4.1.137.Final or 4.2.x < 4.2.17.Final
- Target uses SslClientHelloHandler for SNI-based SslContext selection
- TLS endpoint is network-reachable
- Most Netty deployments use a single SslContext — SNI-based routing with per-host mTLS is a niche pattern
- Netty is typically embedded in higher-level frameworks (Spring WebFlux, gRPC-Java, Vert.x) that abstract away SslClientHelloHandler
Craft a fragmented TLS ClientHello
IndexOutOfBoundsException. No specialized tooling has been publicly released; the attacker would need to use a raw socket or a modified TLS library (e.g., scapy, custom OpenSSL s_client wrapper, or a purpose-built Python script using the struct module).- Ability to send raw TCP/TLS traffic to the target port
- Understanding of TLS record layer framing
- No public PoC or weaponized tool exists as of September 2026
- Requires TLS-layer crafting knowledge, not a point-and-click exploit
Trigger fallback to default SslContext
SslClientHelloHandler#decode to throw IndexOutOfBoundsException. The exception handler invokes select(ctx, null), routing the connection to the default SslContext. If the default context has clientAuth=NONE or clientAuth=OPTIONAL, the TLS handshake completes without requiring a client certificate. The attacker's connection is now established under the permissive default context.- Default SslContext uses clientAuth=NONE or clientAuth=OPTIONAL
- SNI-specific context with clientAuth=REQUIRE is the sole mTLS enforcement point
- Security-conscious deployments set the default context to clientAuth=REQUIRE as well
- Some frameworks (e.g., Spring Cloud Gateway) add application-layer cert checks that would reject the certificate-less session
select(ctx, null) invocations.Access mTLS-protected resources without a client certificate
- No application-layer authentication (e.g., JWT, API key, OAuth) behind the mTLS gate
- Protected route serves sensitive functionality or data
- Defense-in-depth deployments layer application-layer auth on top of mTLS
- Service mesh sidecars (Envoy, Linkerd) may enforce their own mTLS independently of the Netty application
The supporting signals.
| In-the-Wild Exploitation | No evidence of active exploitation as of 2026-09-20. Not listed on CISA KEV. No campaigns or threat actor TTPs observed. |
|---|---|
| Proof-of-Concept | No public PoC exists. The technical mechanism is fully documented in the OX Security analysis and the GHSA advisory, making a PoC straightforward to build for anyone with TLS record-layer knowledge. |
| EPSS | 0.00317 (0.32%) — 24.4th percentile. Low predicted probability of exploitation within 30 days. |
| KEV Status | Not listed. No due date. No binding operational directive applies. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N (9.1) per third-party databases. GitHub advisory rates High. noisgate assessment: AC:H is more accurate → 7.4. |
| Affected Versions | Netty < 4.1.137.Final and 4.2.0.Final through 4.2.16.Final. The netty-handler artifact specifically contains the vulnerable SslClientHelloHandler. |
| Fixed Versions | 4.1.137.Final (4.1.x branch) and 4.2.17.Final (4.2.x branch). Distro backports: check downstream advisories for Spring Boot, Quarkus, gRPC-Java, Elasticsearch, Cassandra BOMs. |
| Scanning / Exposure | Netty does not expose a fingerprint-able banner. Shodan/Censys cannot directly enumerate vulnerable instances. Dependency scanning (Snyk, Dependabot, Trivy, Grype) flags netty-handler JARs — this is the primary detection vector. |
| Disclosure Date | 2026-08-19 (public advisory). GHSA published 2026-09-08. |
| Reporter | violetagg — Netty project contributor / maintainer. |
Why this verdict
- Configuration-gated attack path: The exploit requires three simultaneous conditions — SNI-based SslContext routing with per-host
clientAuth=REQUIRE, a default context with weaker auth, and no app-layer cert check. This is a conjunction of niche settings, not a default configuration. Real-world attack complexity is HIGH, not LOW as the raw CVSS vector claims. - No weaponization yet: Zero public PoC, zero in-the-wild exploitation, not on CISA KEV, and EPSS is 0.32% (24th percentile). The technical writeup is detailed enough to enable exploit development, but nobody has published tooling as of September 2026.
- Massive library footprint, tiny vulnerable surface: Netty is embedded in hundreds of Java frameworks and products (Spring WebFlux, gRPC-Java, Elasticsearch, Cassandra, Play, Vert.x). However,
SslClientHelloHandleris a specialized class — most deployments never instantiate it. The population of actually-exploitable servers is a small fraction of the Netty installed base. - Role multiplier: When SNI-based mTLS IS used, it's typically in high-value roles: (a) API gateways / service mesh ingress — blast radius is access to all backend services, potentially fleet-scale lateral movement; (b) multi-tenant TLS termination — blast radius is cross-tenant access. These roles establish a HIGH floor because the chain succeeds in the high-value role and the outcome is unauthorized access to internal service fabric. However, the affected component is not *canonically* a high-value-role component (Netty is a general-purpose networking library, not an IdP/DC/hypervisor) — fewer than 5% of Netty deployments use the vulnerable SNI mTLS pattern — so the floor is HIGH, not CRITICAL.
- Unauthenticated remote vector preserves severity: Despite the configuration prerequisites, the attack IS network-reachable, requires no credentials, and no user interaction. When conditions are met, impact is high-confidentiality + high-integrity (full mTLS bypass). This prevents dropping below HIGH.
Why not higher?
CRITICAL would require either active exploitation, a canonical high-value-role component (Netty is a general-purpose library, not an identity provider or hypervisor), or a default-configuration attack path. None apply. The three-condition conjunction for exploitability dramatically narrows the vulnerable population. Automated scanners rating this 9.1/CRITICAL are reflecting the theoretical worst-case CVSS vector, not real deployment exposure.
Why not lower?
MEDIUM would undercount the blast radius in the deployments where the conditions ARE met. An mTLS bypass on an API gateway or service mesh ingress gives an unauthenticated remote attacker access to the entire internal service fabric — that's a domain-level impact. The unauthenticated-remote vector with high C+I impact, combined with a fully documented exploit mechanism that any competent attacker could weaponize, keeps this firmly at HIGH.
What to do — in priority order.
- Set the default SslContext to clientAuth=REQUIRE — The root cause of the bypass is falling back to a permissive default. If the default context also requires client certificates, the fallback is harmless. This is a one-line configuration change and the single most effective mitigation. Deploy within 30 days per the noisgate mitigation SLA for HIGH severity.
- Add application-layer certificate verification — In your Netty
ChannelHandlerpipeline, verify the peer certificate's CN/SAN against an allowlist after the TLS handshake completes. This defense-in-depth measure ensures mTLS enforcement doesn't depend solely onSslContextselection. Libraries like Bouncy Castle or standardjavax.net.ssl.SSLSession#getPeerCertificates()make this straightforward. - Deploy TLS-aware IDS rules for anomalous ClientHello records — Write Suricata/Zeek rules to alert on TLS records with handshake payloads under 4 bytes. This is anomalous per RFC 8446 and would detect exploitation attempts. Example:
alert tls any any -> any any (msg:"Suspicious tiny TLS record payload"; flow:to_server; content:|16 03|; depth:2; dsize:<9;). - Upgrade netty-handler to 4.1.137.Final or 4.2.17.Final — The definitive fix. Ensure both direct and transitive dependencies are updated — check your Maven/Gradle BOM. Target within 180 days per the noisgate remediation SLA for HIGH severity. Run
mvn dependency:tree -Dincludes=io.netty:netty-handlerto find all transitive pulls. - Enforce mTLS at the service mesh sidecar layer — If running Istio/Linkerd/Consul Connect, ensure sidecar-level mTLS is enforced independently of the application's Netty configuration. This provides a second authentication gate that the Netty bypass cannot circumvent.
- WAF rules blocking malformed HTTP requests — the bypass occurs at the TLS layer, before any HTTP parsing. A WAF that operates on decrypted HTTP traffic will never see the malicious ClientHello.
- Network-layer firewalling / IP allowlists alone — these control who can reach the port but do not validate whether the TLS handshake enforced client authentication. An attacker from an allowed IP range still bypasses mTLS.
- Upgrading only the application's direct Netty dependency — transitive dependencies through Spring Boot, gRPC-Java, or Elasticsearch client libraries may pin an older netty-handler. You must audit the full dependency tree.
Crowdsourced verification payload.
Run this script on each application host where a Java service uses Netty. It scans for netty-handler JAR files in common deployment paths and checks their version. Requires read access to the filesystem (no root needed). Invoke: bash check_cve_2026_75595.sh /opt/myapp/lib (pass the directory containing your application's JARs).
#!/usr/bin/env bash
# check_cve_2026_75595.sh — Detect CVE-2026-75595 (Netty SslClientHelloHandler mTLS bypass)
# Usage: bash check_cve_2026_75595.sh [search_directory]
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -euo pipefail
SEARCH_DIR="${1:-/}"
VULNERABLE=0
PATCHED=0
FOUND=0
version_gte() {
# Returns 0 if $1 >= $2 using sort -V
[ "$(printf '%s\n%s' "$1" "$2" | sort -V | head -n1)" = "$2" ]
}
echo "[*] Scanning for netty-handler JARs in ${SEARCH_DIR}..."
while IFS= read -r jar; do
FOUND=$((FOUND + 1))
# Extract version from filename: netty-handler-4.1.136.Final.jar
version=$(echo "$jar" | grep -oP 'netty-handler-\K[0-9]+\.[0-9]+\.[0-9]+')
if [ -z "$version" ]; then
# Try reading from META-INF/MANIFEST.MF inside the JAR
version=$(unzip -p "$jar" META-INF/MANIFEST.MF 2>/dev/null | grep -i 'Bundle-Version\|Implementation-Version' | head -1 | grep -oP '[0-9]+\.[0-9]+\.[0-9]+' || true)
fi
if [ -z "$version" ]; then
echo "[?] UNKNOWN version: $jar"
continue
fi
major_minor=$(echo "$version" | cut -d. -f1,2)
if [ "$major_minor" = "4.2" ]; then
if version_gte "$version" "4.2.17"; then
echo "[+] PATCHED ($version): $jar"
PATCHED=$((PATCHED + 1))
else
echo "[-] VULNERABLE ($version < 4.2.17): $jar"
VULNERABLE=$((VULNERABLE + 1))
fi
elif [ "$major_minor" = "4.1" ]; then
if version_gte "$version" "4.1.137"; then
echo "[+] PATCHED ($version): $jar"
PATCHED=$((PATCHED + 1))
else
echo "[-] VULNERABLE ($version < 4.1.137): $jar"
VULNERABLE=$((VULNERABLE + 1))
fi
else
# Versions before 4.1 are also vulnerable
echo "[-] VULNERABLE ($version): $jar"
VULNERABLE=$((VULNERABLE + 1))
fi
done < <(find "$SEARCH_DIR" -name 'netty-handler-*.jar' -type f 2>/dev/null)
echo ""
echo "=== RESULTS ==="
echo "JARs found: $FOUND | Vulnerable: $VULNERABLE | Patched: $PATCHED"
if [ "$FOUND" -eq 0 ]; then
echo "UNKNOWN — no netty-handler JARs found in $SEARCH_DIR"
exit 2
elif [ "$VULNERABLE" -gt 0 ]; then
echo "VULNERABLE — CVE-2026-75595 affects $VULNERABLE JAR(s)"
exit 1
else
echo "PATCHED — all netty-handler JARs are at fixed versions"
exit 0
fiWhat defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.