← Back to Feed CACHED · 2026-10-08 21:45:06 · CACHE_KEY CVE-2026-75596
CVE-2026-75596 · CWE-407 · Disclosed 2026-08-19

Netty SniHandler quadratic-complexity DoS via fragmented ClientHello reassembly

ASSESSED — NOISGATE
Vendor
—
—
—
Reassessed
—
—
—
Verdict: —
Do you agree?
01 · The Real Story

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.

"DoS-only flaw in Netty SniHandler; most enterprises terminate TLS upstream, capping real-world blast radius."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify Netty TLS endpoint with SniHandler

The attacker locates a service that terminates TLS using Netty's 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.
Conditions required:
  • Target service exposes a raw TCP/TLS port using Netty SniHandler
  • No upstream TLS-terminating proxy between attacker and Netty
Where this breaks in practice:
  • 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
STEP 02

Send initial TLS record with inflated ClientHello length

The attacker opens a TCP connection and sends a TLS handshake record whose ClientHello header declares a large body length (e.g., 4,096 bytes). This primes SniHandler to begin accumulating fragments in handshakeBuffer. No authentication or valid certificate is needed — this is pre-handshake.
Conditions required:
  • TCP connectivity to the Netty TLS port
Where this breaks in practice:
  • Network firewalls or IDS may flag unusual TLS record patterns
  • Connection-rate limiting at the transport layer can throttle attempts
Detection/coverage: TLS-aware IDS/IPS (Suricata with JA3/JA4 rules) can detect anomalous ClientHello fragmentation patterns, though no specific signature is widely deployed for this CVE.
STEP 03

Drip thousands of tiny handshake fragments

The attacker sends the ClientHello body as thousands of 1-byte TLS records. On each record, 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.
Conditions required:
  • Sustained TCP session to deliver ~4,095 tiny records
Where this breaks in practice:
  • 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
Detection/coverage: CPU spike on the JVM process handling TLS; event loop latency metrics in Netty (if instrumented) would show handler stalls.
STEP 04

Event loop CPU exhaustion

The quadratic copy work saturates one or more event loop threads. All TLS handshakes sharing those threads stall, causing connection timeouts and service degradation for legitimate users. The attacker can sustain this with minimal bandwidth by opening multiple connections and repeating the pattern. Impact is availability loss — there is no path to code execution, data exfiltration, or privilege escalation.
Conditions required:
  • Successful delivery of fragmented ClientHello per step 3
Where this breaks in practice:
  • 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
Detection/coverage: JVM thread dumps showing event loop threads stuck in buffer copy operations; application-level health checks failing; load balancer marking backend unhealthy.
03 · Compensating Control

1
MEDIUM 5.8→IGNORE 0.0
SEVERITY REDUCED
Terminate TLS upstream of Netty — Place an L7 load balancer, reverse proxy (nginx, HAProxy, Envoy), or CDN in front of the Netty service to handle TLS termination. This ensures Netty's 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.
2
MEDIUM 5.8→LOW 3.2
SEVERITY REDUCED
Limit concurrent TCP connections per source IP — Configure network-level connection rate limiting (iptables 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.
3
MEDIUM 5.8→LOW 3.8
SEVERITY REDUCED
Set a TLS handshake timeout — Configure a short handshake timeout (e.g., 5-10 seconds) on the Netty pipeline using 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.
4
MEDIUM 5.8→IGNORE 0.0
SEVERITY REDUCED
Upgrade netty-handler to ≥ 4.1.137.Final or ≥ 4.2.17.Final — The definitive fix. Update the 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.
What doesn't work
  • 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 maxContentLength or HttpObjectAggregator limits — These apply to HTTP-layer content aggregation, not pre-handshake TLS record reassembly. The vulnerability fires before any HTTP processing begins.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone 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 availabilityNo 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.
EPSS0.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 statusNot listed. No CISA KEV entry as of 2026-10-09.
CVSS vectorCVSS: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 versionsio.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 versions4.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 & exposureNo 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 date2026-08-19 via GitHub Security Advisory GHSA-fccg-mwvh-qqg4. Coordinated disclosure with fix available at announcement.
Reporting researcherLiyi 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.

  1. GitHub Security Advisory (GHSA-fccg-mwvh-qqg4)
  2. GitLab Advisory Database — CVE-2026-75596
  3. OpenCVE — CVE-2026-75596
  4. OSV — GHSA-fccg-mwvh-qqg4
  5. Keycloak tracking issue
  6. DailyCVE — CVE-2026-75596 writeup
  7. FIRST EPSS data
  8. Strix.ai — CVE-2026-75596
05 · The Call

Final Verdict
↓ DOWNGRADED to MEDIUM (5.8/10)

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 SniHandler and SslClientHelloHandler. Netty services that use SslHandler directly (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.

06 · Verification

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.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/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