Like a postal clerk who photocopies the entire mailbag every time a new letter arrives
CVE-2026-75596 is a quadratic-complexity denial-of-service in Netty's SniHandler and SslClientHelloHandler. When an unauthenticated remote peer sends a fragmented TLS ClientHello — advertising a large handshake length but delivering the body in thousands of 1-byte TLS records — the handler calls handshakeBuffer.clear() then writeBytes() for every fragment, recopying *all* previously accumulated bytes each time. With 4,095 one-byte fragments the library copies 8,386,560 bytes from only 24,579 bytes on the wire, a 341× amplification ratio. This pins the Netty event loop's CPU and degrades or freezes TLS processing for every other client on that loop. Affected versions are netty-handler < 4.1.137.Final and 4.2.0.Final through 4.2.16.Final; fixed in 4.1.137.Final and 4.2.17.Final.
The vendor CVSS 3.1 score of 7.5 HIGH is mechanically correct — unauthenticated, network-accessible, low-complexity, high availability impact — but it overstates the real-world risk. The GHSA maintainers themselves rated it Moderate (CVSS v4: 6.9), and that instinct is closer to reality. The flaw is DoS-only with zero confidentiality or integrity impact; it specifically targets SniHandler, which is only in play when Netty is doing its own TLS termination with SNI-based routing; and a large fraction of enterprise Java services sit behind load balancers, CDNs, or API gateways that terminate TLS upstream, meaning Netty's SniHandler never sees raw ClientHello fragments. There is no known exploitation in the wild, no public PoC on pocindex.io or GitHub, and EPSS puts the 30-day exploitation probability at 0.374% (28th percentile). This is a real flaw that should be patched in normal maintenance cycles, not an emergency.
4 steps from start to impact.
Identify Netty TLS endpoint with SniHandler
SniHandler or SslClientHelloHandler. This is identifiable by probing for SNI-based certificate selection behavior or by fingerprinting the TLS implementation through timing and extension ordering. Services behind a CDN, WAF, or external load balancer that terminates TLS are not reachable for this attack.- Target service exposes a raw TCP/TLS port using Netty SniHandler
- No upstream TLS-terminating proxy between attacker and Netty
- Many enterprise deployments put Netty behind an L7 LB or CDN that terminates TLS, making SniHandler unreachable
- Cloud-native deployments often use sidecar proxies (Envoy/Istio) for TLS, not Netty's built-in handler
Send initial TLS record with inflated ClientHello length
SniHandler to begin accumulating fragments in handshakeBuffer. No authentication or valid certificate is needed — this is pre-handshake.- TCP connectivity to the Netty TLS port
- Network firewalls or IDS may flag unusual TLS record patterns
- Connection-rate limiting at the transport layer can throttle attempts
Drip thousands of tiny handshake fragments
SniHandler calls handshakeBuffer.clear() followed by writeBytes(previousBytes), recopying the entire accumulated buffer. With N fragments, the total bytes copied grows as O(N²). At 4,095 fragments, 8.4 MB of internal copies are triggered from ~25 KB on the wire.- Sustained TCP session to deliver ~4,095 tiny records
- TCP-level rate limiting or minimum segment size enforcement can slow this
- Netty's event loop thread count limits the parallelism of the attack — degradation may be per-loop, not total
Event loop CPU exhaustion
- Successful delivery of fragmented ClientHello per step 3
- Well-configured deployments use multiple event loop groups; the attacker must saturate all to achieve full DoS
- Health-check-based autoscaling or load balancer failover may route traffic away from the degraded instance
SniHandler never processes raw ClientHello records from untrusted sources. This is the single most effective mitigation and is already the architecture for most enterprise deployments. No mitigation SLA applies at MEDIUM — go straight to the 365-day remediation window for the actual Netty upgrade.connlimit, cloud security group rules, or application-level Netty ChannelHandler limits) to cap the number of simultaneous half-open TLS handshakes from any single IP. This limits the attacker's ability to saturate multiple event loops. Deploy as part of normal hardening within the 365-day remediation window.ReadTimeoutHandler or SslHandler.setHandshakeTimeout(). This bounds the window for the quadratic copy to complete and forces cleanup of stalled connections. Not a fix — the CPU spike still occurs during the timeout window — but limits sustained impact.io.netty:netty-handler dependency in your Maven/Gradle build. For transitive dependencies (Spring Boot, gRPC, Keycloak, etc.), check whether the parent framework has released a version pulling the fixed Netty. Under the noisgate remediation SLA for MEDIUM, apply within 365 days. If the service directly exposes SniHandler to the internet without upstream TLS termination, treat as HIGH-equivalent and expedite to 30 days.- WAF rules — The attack uses valid TLS record framing at the TCP layer. Web Application Firewalls operate at HTTP (L7) and cannot inspect or block pre-handshake TLS record fragmentation patterns. A WAF sitting behind TLS termination never sees the malicious records.
- JVM heap tuning — The bottleneck is CPU (quadratic byte copies on the event loop thread), not memory. Increasing heap or tuning GC does not reduce the copy amplification.
- Netty
maxContentLengthorHttpObjectAggregatorlimits — These apply to HTTP-layer content aggregation, not pre-handshake TLS record reassembly. The vulnerability fires before any HTTP processing begins.
The supporting signals.
| In-the-wild exploitation | None observed. Not listed in CISA KEV. No campaigns, advisories, or threat intel reports reference active exploitation of this CVE as of 2026-10-09. |
|---|---|
| Proof-of-concept availability | No public PoC. pocindex.io returns no results. No GitHub repositories named after CVE-2026-75596. The GHSA advisory includes a conceptual reproduction description (fragment count, amplification ratio) but no weaponized script. Trivial to implement from the advisory description alone — a basic Python/Go TLS record crafter would suffice. |
| EPSS | 0.00374 (0.374%), 28th percentile. Well below the exploitation-likely threshold. Consistent with a DoS-only flaw with no public PoC and no wild exploitation. |
| KEV status | Not listed. No CISA KEV entry as of 2026-10-09. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H → 7.5 HIGH. Pure availability impact — C:N/I:N means no data-at-risk component. GHSA rates CVSS v4 at 6.9 Moderate with VA:L (low availability in v4 terms). |
| Affected versions | io.netty:netty-handler versions < 4.1.137.Final (all 4.1.x releases) and 4.2.0.Final through 4.2.16.Final. The flaw is in SniHandler and SslClientHelloHandler default constructors. Netty arrives transitively via Spring Boot (Reactor Netty), gRPC-Java, Elasticsearch transport client, Cassandra drivers, Keycloak, Vert.x, and many others. |
| Fixed versions | 4.1.137.Final and 4.2.17.Final. Fix commits: 9e0519239108a69b7e9bbc5e9182ee139a0d7961 (4.1.x branch), 1b5abc6443b63726c72cdd285af2feb7ddbb8ff7 (4.2.x branch). Corresponding PRs: #17213, #17217. |
| Scanning & exposure | No GreyNoise tags or Shodan dorks specific to this CVE. Netty does not expose a version banner in TLS handshakes, making passive internet scanning impractical. Detection requires JAR-level inspection or SBOM analysis. SniHandler usage is a subset of all Netty TLS deployments — only services doing SNI-based routing are affected. |
| Disclosure date | 2026-08-19 via GitHub Security Advisory GHSA-fccg-mwvh-qqg4. Coordinated disclosure with fix available at announcement. |
| Reporting researcher | Liyi Zhou, Ziyue Wang, Strick, Maurice (@mauriceng98), Chenchen Yu — University of Sydney security research team. Advisory notes AI-assisted discovery with independent reproduction and validation. |
Sources.
Why this verdict
- DoS-only ceiling: The CVSS 3.1 vector explicitly shows C:N/I:N/A:H — there is zero path to code execution, data exfiltration, or lateral movement. The worst-case outcome on any host is a service restart, not a compromise. This caps the practical severity below HIGH for patching priority purposes.
- SniHandler-specific scope: The flaw lives exclusively in
SniHandlerandSslClientHelloHandler. Netty services that useSslHandlerdirectly (without SNI routing) are unaffected. This narrows the vulnerable population to a subset of Netty TLS users — those doing multi-tenant or virtual-host TLS termination in-process. - Upstream TLS termination is pervasive: Enterprise Java services routinely sit behind AWS ALB/NLB, Cloudflare, nginx, HAProxy, Envoy sidecars (Istio/Linkerd), or F5 — all of which terminate TLS before traffic reaches Netty. In these architectures, Netty's SniHandler never processes raw ClientHello records, making the flaw unreachable. This covers a large majority of production deployments.
- No exploitation signal: Zero KEV listing, zero in-the-wild campaigns, no public PoC on pocindex.io or GitHub, EPSS at 0.374% (28th percentile). The GHSA maintainers themselves rated it Moderate (CVSS v4: 6.9), a meaningful downward signal from the people who wrote the code.
- Role multiplier: Netty is embedded in high-value components — Keycloak (identity provider), Elasticsearch (SIEM/analytics), gRPC services (inter-service mesh), Cassandra (data tier). A successful DoS against Keycloak's TLS endpoint could deny authentication org-wide, which is operationally painful. However, (1) the outcome remains *availability loss*, not identity compromise, domain takeover, or data exfiltration — none of the catastrophic outcomes that trigger the HIGH/CRITICAL floor; (2) Keycloak in production almost universally sits behind a reverse proxy (nginx, HAProxy, or Kubernetes ingress) that terminates TLS, so the SniHandler path is rarely reachable; (3) the same applies to Elasticsearch and Cassandra, which typically use internal transport encryption not exposed to untrusted networks. The blast radius at worst is *single-service DoS on a directly-exposed instance*, not fleet-scale or identity-scale compromise.
Why not higher?
The impact ceiling is availability loss — there is no confidentiality or integrity damage, no privilege escalation, and no path from this DoS to code execution or lateral movement. Even in the worst-case high-value role scenario (DoS of a directly-exposed Keycloak instance), the outcome is a service outage that is recoverable by restart, not a domain compromise. The GHSA maintainers concur with a Moderate rating.
Why not lower?
The attack is unauthenticated, requires no user interaction, and needs only ~25 KB of bandwidth for a 341× amplification ratio — making it trivially weaponizable by anyone who can write a TLS record. Services that *do* expose Netty SniHandler directly to untrusted networks (smaller shops without upstream TLS termination, self-hosted gRPC endpoints, direct-to-internet Java services) are genuinely vulnerable with no friction. The flaw is also easy to re-derive from the advisory description even without a public PoC, so the current 'no PoC' status is a temporary condition.
Crowdsourced verification payload.
Run on each host where a Java service uses Netty for TLS termination. Execute as any user with read access to the application's classpath JARs. Example: bash check_cve_2026_75596.sh /opt/myapp/lib. No root required.
#!/usr/bin/env bash
# check_cve_2026_75596.sh — Detect netty-handler versions vulnerable to CVE-2026-75596
# Usage: bash check_cve_2026_75596.sh <search_directory>
# Exit codes: 0 = PATCHED/not found, 1 = VULNERABLE, 2 = UNKNOWN
set -euo pipefail
SEARCH_DIR="${1:-.}"
VULNERABLE=0
FOUND=0
echo "[*] Scanning for netty-handler JARs under: $SEARCH_DIR"
while IFS= read -r -d '' jar; do
FOUND=1
filename=$(basename "$jar")
# Extract version from filename like netty-handler-4.1.136.Final.jar
if [[ "$filename" =~ netty-handler-([0-9]+)\.([0-9]+)\.([0-9]+) ]]; then
major="${BASH_REMATCH[1]}"
minor="${BASH_REMATCH[2]}"
patch="${BASH_REMATCH[3]}"
version="$major.$minor.$patch"
is_vuln=0
if [[ "$major" -eq 4 && "$minor" -eq 1 ]]; then
# 4.1.x: vulnerable if patch < 137
if [[ "$patch" -lt 137 ]]; then
is_vuln=1
fi
elif [[ "$major" -eq 4 && "$minor" -eq 2 ]]; then
# 4.2.x: vulnerable if patch < 17
if [[ "$patch" -lt 17 ]]; then
is_vuln=1
fi
elif [[ "$major" -lt 4 ]]; then
is_vuln=1
elif [[ "$major" -eq 4 && "$minor" -lt 1 ]]; then
is_vuln=1
fi
if [[ "$is_vuln" -eq 1 ]]; then
echo "VULNERABLE — $jar (version $version)"
VULNERABLE=1
else
echo "PATCHED — $jar (version $version)"
fi
else
# Try reading version from META-INF inside JAR
if command -v unzip &>/dev/null; then
manifest_ver=$(unzip -p "$jar" META-INF/MANIFEST.MF 2>/dev/null | grep -i 'Bundle-Version\|Implementation-Version' | head -1 | awk -F': ' '{print $2}' | tr -d '\r' || true)
if [[ -n "$manifest_ver" ]]; then
echo "UNKNOWN — $jar (manifest version: $manifest_ver — verify manually)"
else
echo "UNKNOWN — $jar (could not determine version)"
fi
else
echo "UNKNOWN — $jar (could not determine version; install unzip for manifest check)"
fi
fi
done < <(find "$SEARCH_DIR" -type f -name 'netty-handler-*.jar' -print0 2>/dev/null)
# Also check for shaded/uber JARs containing netty handler
while IFS= read -r -d '' jar; do
if command -v unzip &>/dev/null; then
if unzip -l "$jar" 2>/dev/null | grep -q 'io/netty/handler/ssl/SniHandler'; then
FOUND=1
echo "WARNING — $jar contains shaded netty SniHandler — check version manually"
fi
fi
done < <(find "$SEARCH_DIR" -type f -name '*.jar' ! -name 'netty-handler-*' -print0 2>/dev/null)
if [[ "$FOUND" -eq 0 ]]; then
echo "PATCHED — No netty-handler JARs found under $SEARCH_DIR"
exit 0
elif [[ "$VULNERABLE" -eq 1 ]]; then
exit 1
else
exit 0
fi