← Back to Feed CACHED · 2026-09-20 05:43:21 · CACHE_KEY CVE-2026-56853
CVE-2026-56853 · CWE-770 · Disclosed 2026-08-13

When a server is configured to support unencrypted HTTP/2

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

Leaving your screen door open only matters if you built a screen door in the first place

CVE-2026-56853 is a resource-exhaustion flaw in Go's net/http standard library. When a server explicitly enables unencrypted HTTP/2 (h2c) via Server.Protocols.SetUnencryptedHTTP2(true), the server peeks at the first bytes of every inbound connection to detect the HTTP/2 client connection preface. That initial read was not governed by ReadHeaderTimeout, so a malicious client could open a TCP connection, send zero bytes, and hold that connection open forever. Repeat this thousands of times and the server's file-descriptor or goroutine pool is exhausted — classic Slowloris-style denial of service. Affected versions: Go < 1.25.13, Go 1.26.0–1.26.5, and Go 1.27.0-0 pre-releases. Fixed in Go 1.25.13, Go 1.26.6, and Go 1.27.0-rc.3.

The vendor CVSS of 7.5 HIGH is technically correct for the narrow scenario where h2c is enabled and the server is directly reachable — unauthenticated, network-accessible, low complexity, availability-only impact. But it overstates real-world risk significantly. h2c is not enabled by default in Go's net/http; it requires an explicit opt-in added in Go 1.24 (mid-2025). The vast majority of Go HTTP servers in production terminate TLS at the server or sit behind a TLS-terminating reverse proxy, neither of which triggers this code path. Even when h2c *is* enabled — typically behind a load balancer for gRPC backends or Cloud Run — the load balancer itself enforces idle timeouts that cap the Slowloris window. The impact ceiling is service availability disruption, not data compromise or code execution.

"DoS-only bug requires h2c opt-in that almost nobody enables in production"
02 · The Attack Path

3 steps from start to impact.

STEP 01

Identify h2c-enabled Go server

The attacker scans for Go HTTP servers that accept cleartext HTTP/2 connections. This requires the target to have explicitly set UnencryptedHTTP2 in its Server.Protocols configuration — a non-default setting introduced in Go 1.24. Servers behind TLS or running HTTP/1.1-only are not vulnerable.
Conditions required:
  • Target runs a Go HTTP server with h2c explicitly enabled
  • Target is network-reachable on the h2c-serving port
Where this breaks in practice:
  • h2c is opt-in, not default — the overwhelming majority of Go servers do not enable it
  • Most h2c deployments sit behind TLS-terminating load balancers or reverse proxies, not directly exposed
Detection/coverage: No specific scanner signature exists; detection requires banner-grabbing for h2c upgrade or PRI method support.
STEP 02

Open TCP connections, send nothing

The attacker opens thousands of TCP connections to the target port and deliberately sends zero bytes on each. Because ReadHeaderTimeout is not applied during the h2c preface detection phase, the server's goroutine for each connection blocks indefinitely on the initial Read() call. Each idle connection consumes a goroutine (~4-8 KB stack) and a file descriptor.
Conditions required:
  • Network connectivity to the h2c port
  • No upstream connection-rate limiting or idle-timeout enforcement
Where this breaks in practice:
  • Any reverse proxy, load balancer, or cloud LB in front enforces its own idle timeouts (typically 60-300s), killing the stalled connections before damage accumulates
  • OS-level ulimit and net.core.somaxconn provide a natural ceiling on open connections
  • Cloud WAFs and DDoS protection services (Cloudflare, AWS Shield, GCP Cloud Armor) drop idle connections
Detection/coverage: Monitoring goroutine count or open file descriptors on the Go process would surface the anomaly. netstat or ss showing thousands of ESTABLISHED connections with zero bytes transferred is a clear signal.
STEP 03

Exhaust server resources

Once the attacker holds enough idle connections to consume all available file descriptors or goroutine memory, the server can no longer accept new connections. Legitimate clients receive connection-refused errors. The impact is a denial of service affecting availability only — no data is disclosed and no code is executed.
Conditions required:
  • Sufficient idle connections held open past the missing timeout
  • No external circuit breaker or auto-scaling in place
Where this breaks in practice:
  • Kubernetes deployments with liveness probes and replica sets will restart or reschedule the affected pod, limiting outage duration
  • Connection limits per source IP at the firewall or LB layer cap the attacker's leverage from a single origin
  • The attack requires sustained connection holding, not a single burst — making it easier to detect and block in real time
Detection/coverage: Standard availability monitoring (health checks, latency alerts, goroutine metrics via runtime.NumGoroutine(), Prometheus go_goroutines gauge) will trigger alerts well before full exhaustion.
03 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNone observed. Not listed in CISA KEV. No campaigns or threat-actor usage documented as of 2026-09-20.
Proof of ConceptNo public PoC. The attack is trivially reproducible (open TCP sockets, send nothing) but no named researcher or repo has published weaponized tooling.
EPSS Score0.00568 (0.57%) — bottom quartile. FIRST's model rates exploitation probability as very low.
KEV StatusNot listed. No CISA KEV entry as of 2026-09-20.
CVSS VectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — Network-reachable, no auth, availability-only. The vector is accurate *if* h2c is enabled; it does not encode the opt-in prerequisite.
Affected VersionsGo < 1.25.13, Go 1.26.0–1.26.5, Go 1.27.0-0 pre-releases. Downstream: KrakenD CE < 2.13.9, KrakenD EE < 2.13.7, Docker CLI (backport pending).
Fixed VersionsGo 1.25.13, 1.26.6, 1.27.0-rc.3. Distro backports: RHEL/Fedora via RHSA-2026:68335, Debian tracking via DSA.
Scanning / ExposureNo GreyNoise or Shodan tags specific to this CVE. h2c servers are uncommon in internet-facing scan data; most HTTP/2 endpoints negotiate via ALPN over TLS.
Disclosure Date2026-08-13 (Go security release). Issue tracked as golang/go#80205, reserved 2026-06-23.
ReporterReported via Go's security process. Assigned to @neild (Damien Neil, Go team). CL 795540.
04 · The Call

Final Verdict
DOWNGRADED to MEDIUM (5.3/10)

Why this verdict

  • Non-default configuration required: h2c (UnencryptedHTTP2) must be explicitly enabled in Go's Server.Protocols — it is off by default. This is not a latent-everywhere condition like a stdlib parsing bug; it gates the entire attack path on a deliberate, uncommon configuration choice. Conservative estimate: <5% of Go HTTP server deployments enable h2c.
  • Availability-only impact ceiling: The CVSS vector correctly shows C:N/I:N/A:H. There is no path from this bug to code execution, data exfiltration, lateral movement, or privilege escalation. The worst-case outcome at any deployment role is a temporary service outage.
  • Infrastructure friction is high: Production h2c servers almost universally sit behind load balancers, reverse proxies, or service meshes (Envoy, Istio, cloud LBs) that enforce their own idle-connection timeouts. The Slowloris window rarely survives the intermediary layer.
  • Role multiplier: Go's net/http powers high-value components — Kubernetes API server, etcd, Docker, Vault, Traefik, Caddy. However: (a) kube-apiserver and etcd serve TLS by default, not h2c; (b) Vault, Traefik, and Caddy default to TLS; (c) even if a high-value component *did* enable h2c internally, the blast radius is availability loss of that single service, not domain takeover, fleet compromise, or data egress. The HIGH floor does not engage because no realistic high-value-role outcome reaches the enumerated catastrophic thresholds (domain takeover / fleet compromise / mass data egress / supply-chain pivot / OT-safety impact). DoS of an internal service is disruptive but recoverable and does not cascade to identity or data compromise.
  • No exploitation signal: EPSS 0.57%, no KEV listing, no known PoC, no observed campaigns. The attack is simple in theory but has attracted zero real-world interest five weeks post-disclosure.

Why not higher?

Upgrading to HIGH would require either a realistic path beyond availability impact or evidence that a significant share of the installed base runs h2c in a position where DoS translates to safety or cascading infrastructure failure. Neither condition is met. The h2c opt-in gates the chain so severely that the network-reachable, no-auth vector overstates actual exposure. DoS of a single Go service behind a load balancer is a recoverable operational event, not a security catastrophe.

Why not lower?

Dropping to LOW would understate the risk for the minority of deployments that *do* run h2c on directly exposed services without an intermediary. In that configuration, the attack is trivial (no auth, no complexity, no user interaction), and resource exhaustion is reliable. The theoretical CVSS vector is valid for that population, and Go's net/http is widely enough deployed that even a small percentage of h2c adopters represents a non-trivial number of hosts.

05 · Compensating Control

What to do — in priority order.

  1. Disable h2c if not required — If your Go services do not need cleartext HTTP/2, ensure UnencryptedHTTP2 is not set in Server.Protocols. This eliminates the vulnerable code path entirely. No noisgate mitigation SLA applies at MEDIUM — go straight to the 365-day remediation window for the Go upgrade.
  2. Enforce idle-connection timeouts at the load balancer — Configure your reverse proxy or load balancer (NGINX, Envoy, HAProxy, cloud LB) to enforce an idle timeout of 60–120 seconds on backend connections. This caps the Slowloris window regardless of the Go bug.
  3. Set OS-level connection limits — Use ulimit -n and sysctl net.core.somaxconn to cap the maximum number of open file descriptors per process. This provides a hard ceiling on resource exhaustion and forces connection recycling.
  4. Monitor goroutine count — Add alerting on go_goroutines (Prometheus) or runtime.NumGoroutine(). A spike in goroutines with zero active requests is a reliable signal of idle-connection abuse. Alert at 2× your baseline p99.
  5. Upgrade Go runtime to 1.25.13 / 1.26.6 / 1.27.0+ — The definitive fix. Rebuild and redeploy your Go binaries against a patched Go toolchain. Under the noisgate remediation SLA for MEDIUM, complete this within 365 days. Prioritize services that directly expose h2c to untrusted networks.
What doesn't work
  • TLS configuration hardening — the bug is exclusively in the *unencrypted* HTTP/2 path. If you already use TLS (h2 via ALPN), you are not affected and TLS tuning changes nothing.
  • ReadTimeout or WriteTimeout on the Go server — these timeouts apply *after* the initial protocol detection, not during the h2c preface peek. Only ReadHeaderTimeout was missing, and only during the preface phase.
  • IP-based rate limiting alone — Slowloris attacks can originate from many IPs (botnets); per-IP connection limits help but don't fully solve the problem without idle-timeout enforcement.
06 · Verification

Crowdsourced verification payload.

Run on or from any host where the target Go service is reachable. Pass the target's h2c endpoint as an argument: bash check_cve_2026_56853.sh myservice.internal:8080. Requires curl (≥7.86 for --http2-prior-knowledge) and go version if checking locally. No elevated privileges needed.

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_56853.sh — Detect CVE-2026-56853 exposure
# Tests whether a Go HTTP server accepts h2c AND holds idle connections
# Usage: bash check_cve_2026_56853.sh <host:port> [timeout_seconds]
# Exit codes: 0=VULNERABLE, 1=PATCHED, 2=UNKNOWN

set -euo pipefail

TARGET="${1:-}"
TIMEOUT="${2:-10}"

if [[ -z "$TARGET" ]]; then
  echo "Usage: $0 <host:port> [timeout_seconds]"
  exit 2
fi

echo "[*] Testing h2c support on $TARGET ..."

# Step 1: Check if the server accepts h2c at all
H2C_CHECK=$(curl -s -o /dev/null -w '%{http_version}' \
  --http2-prior-knowledge \
  --max-time 5 \
  "http://$TARGET/" 2>/dev/null || true)

if [[ "$H2C_CHECK" != "2" ]]; then
  echo "PATCHED — Server does not accept unencrypted HTTP/2 (h2c). Not vulnerable."
  exit 1
fi

echo "[*] Server accepts h2c. Testing idle connection hold ..."

# Step 2: Open a raw TCP connection, send nothing, see if it stays open
# beyond the expected ReadHeaderTimeout window
# We use bash /dev/tcp or nc to hold an idle connection
START=$(date +%s)
if command -v nc &>/dev/null; then
  timeout "$TIMEOUT" nc -w "$TIMEOUT" "${TARGET%%:*}" "${TARGET##*:}" </dev/null >/dev/null 2>&1 &
  NC_PID=$!
  sleep "$TIMEOUT"
  if kill -0 "$NC_PID" 2>/dev/null; then
    kill "$NC_PID" 2>/dev/null || true
    HELD=true
  else
    wait "$NC_PID" 2>/dev/null || true
    HELD=false
  fi
else
  echo "[!] nc (netcat) not found. Install netcat for idle-connection test."
  echo "UNKNOWN — Could not complete idle connection test."
  exit 2
fi

END=$(date +%s)
DURATION=$((END - START))

if [[ "$HELD" == "true" && "$DURATION" -ge "$TIMEOUT" ]]; then
  echo "VULNERABLE — Server held idle h2c connection for ${DURATION}s with no data sent."
  echo "CVE-2026-56853: ReadHeaderTimeout not applied during h2c preface check."
  exit 0
else
  echo "PATCHED — Server closed idle connection within ${DURATION}s. ReadHeaderTimeout appears enforced."
  exit 1
fi
07 · Sources

Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.