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.
3 steps from start to impact.
Identify h2c-enabled Go server
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.- Target runs a Go HTTP server with h2c explicitly enabled
- Target is network-reachable on the h2c-serving port
- 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
Open TCP connections, send nothing
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.- Network connectivity to the h2c port
- No upstream connection-rate limiting or idle-timeout enforcement
- 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
ulimitandnet.core.somaxconnprovide a natural ceiling on open connections - Cloud WAFs and DDoS protection services (Cloudflare, AWS Shield, GCP Cloud Armor) drop idle connections
netstat or ss showing thousands of ESTABLISHED connections with zero bytes transferred is a clear signal.Exhaust server resources
- Sufficient idle connections held open past the missing timeout
- No external circuit breaker or auto-scaling in place
- 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
runtime.NumGoroutine(), Prometheus go_goroutines gauge) will trigger alerts well before full exhaustion.The supporting signals.
| In-the-Wild Exploitation | None observed. Not listed in CISA KEV. No campaigns or threat-actor usage documented as of 2026-09-20. |
|---|---|
| Proof of Concept | No public PoC. The attack is trivially reproducible (open TCP sockets, send nothing) but no named researcher or repo has published weaponized tooling. |
| EPSS Score | 0.00568 (0.57%) — bottom quartile. FIRST's model rates exploitation probability as very low. |
| KEV Status | Not listed. No CISA KEV entry as of 2026-09-20. |
| CVSS Vector | CVSS: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 Versions | Go < 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 Versions | Go 1.25.13, 1.26.6, 1.27.0-rc.3. Distro backports: RHEL/Fedora via RHSA-2026:68335, Debian tracking via DSA. |
| Scanning / Exposure | No 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 Date | 2026-08-13 (Go security release). Issue tracked as golang/go#80205, reserved 2026-06-23. |
| Reporter | Reported via Go's security process. Assigned to @neild (Damien Neil, Go team). CL 795540. |
Why this verdict
- Non-default configuration required: h2c (
UnencryptedHTTP2) must be explicitly enabled in Go'sServer.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/httppowers 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.
What to do — in priority order.
- Disable h2c if not required — If your Go services do not need cleartext HTTP/2, ensure
UnencryptedHTTP2is not set inServer.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. - 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.
- Set OS-level connection limits — Use
ulimit -nandsysctl net.core.somaxconnto cap the maximum number of open file descriptors per process. This provides a hard ceiling on resource exhaustion and forces connection recycling. - Monitor goroutine count — Add alerting on
go_goroutines(Prometheus) orruntime.NumGoroutine(). A spike in goroutines with zero active requests is a reliable signal of idle-connection abuse. Alert at 2× your baseline p99. - 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.
- 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.
ReadTimeoutorWriteTimeouton the Go server — these timeouts apply *after* the initial protocol detection, not during the h2c preface peek. OnlyReadHeaderTimeoutwas 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.
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.
#!/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
fiWhat defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.