Leaving the faucet running so the water heater never stops burning gas
CVE-2026-56862 is a denial-of-service vulnerability in Go's standard library crypto/tls package. In TLS 1.3, a KeyUpdate message instructs the peer to derive a fresh set of traffic keys — an intentionally expensive cryptographic operation. Go's implementation treated every KeyUpdate as "state-advancing" and imposed no rate limit on how many a remote peer could send, even after the handshake was already complete. A malicious client can open a single TLS 1.3 connection and flood it with KeyUpdate messages, pinning a server goroutine to continuous HKDF-Expand-Label derivations and consuming CPU indefinitely. Affected versions span every supported Go release branch: anything before go1.25.13, go1.26.0 through go1.26.5, and go1.27.0 through go1.27.0-rc.2. The fix (go1.25.13, go1.26.6, go1.27.0-rc.3) bounds how often rekeying is honored.
The vendor's CVSS 7.5 HIGH rating is technically correct on paper — the vector is unauthenticated, network-reachable, low-complexity, and availability-impacting. But in practice it overstates the risk for most enterprise fleets. First, this is availability-only: no confidentiality leak, no integrity compromise, no code execution. Second, the dominant deployment pattern for Go services in production puts them behind a TLS-terminating reverse proxy (nginx, Envoy, HAProxy, AWS ALB/NLB, GCP Cloud Load Balancer), meaning the Go process never sees raw TLS records and is completely shielded. Third, the DoS is connection-scoped — an attacker must maintain active connections to sustain the CPU burn, and standard connection-timeout and concurrency-limit configurations bound the blast radius. Ubuntu's security team independently downgraded this to Medium priority. noisgate agrees: for most enterprises, this is a MEDIUM.
4 steps from start to impact.
Identify a Go TLS 1.3 endpoint
testssl.sh, nmap --script ssl-enum-ciphers, or custom Go clients can fingerprint the TLS implementation. Services directly exposed include self-hosted Go APIs, Kubernetes API servers without an external LB, and internal microservices communicating via mTLS.- Network reachability to the TLS endpoint (external or internal)
- Target must negotiate TLS 1.3 (default in Go ≥1.13)
- Most production Go services sit behind nginx, Envoy, or cloud LBs that terminate TLS before the Go process
- Internal-only services require the attacker to already have network access inside the perimeter
Establish a TLS 1.3 connection
s_client suffices. The connection enters the application-data phase normally.- Ability to complete a TLS 1.3 handshake (no client cert required unless server enforces mTLS)
- If the server enforces mutual TLS (mTLS), the attacker needs a valid client certificate, which significantly narrows the attacker population
- Connection rate limiting or SYN cookies at the network edge may slow establishment
Flood KeyUpdate messages
KeyUpdate messages (record type 0x16, handshake type 24). Each message is only 5 bytes of TLS record payload. Because Go's crypto/tls treats these as state-advancing, they bypass the non-advancing record limit that would otherwise throttle junk records. The server dutifully derives a new set of traffic keys for every single message.- Active TLS 1.3 connection to the target
- No intermediary that strips or filters post-handshake TLS records
- A TLS-terminating reverse proxy absorbs the KeyUpdate messages — the Go backend never sees them
- Connection idle timeouts (typically 60–120s) limit the duration of any single attack connection
- Per-connection concurrency limits bound how many goroutines an attacker can pin simultaneously
pprof, runtime metrics) would show elevated crypto/tls CPU time.Sustained CPU exhaustion
KeyUpdate triggers HKDF-Expand-Label key derivation, which is computationally expensive relative to a 5-byte trigger message. With hundreds of connections each sending thousands of KeyUpdate messages per second, the attacker can saturate the server's CPU cores. The effect persists only while the attacker maintains the connections — this is not an amplification attack and there is no persistent damage. Service resumes once the malicious connections are dropped.- Sufficient bandwidth to maintain multiple concurrent TLS connections
- Target server has no connection-level rate limiting
- Auto-scaling infrastructure (Kubernetes HPA, cloud auto-scale groups) can absorb transient CPU spikes
- Goroutine and connection limits (
http.Server.MaxConns,net.Listenerwrappers) cap the blast radius - Watchdog processes and health checks restart unresponsive pods/services, limiting downtime window
The supporting signals.
| In-the-wild exploitation | No known exploitation. Not listed in CISA KEV. No threat campaigns or APT usage reported as of 2026-09-20. |
|---|---|
| Proof-of-concept | No public PoC repository found. However, the attack is trivially constructable — a Go client sending KeyUpdate in a loop requires ~20 lines of code. No weaponized tooling (Metasploit, Nuclei template) identified. |
| EPSS | 0.57% probability of exploitation in the next 30 days (44.9th percentile). Below the typical action threshold of 10%. |
| KEV status | Not listed in CISA Known Exploited Vulnerabilities catalog. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — Unauthenticated network DoS, no scope change, availability-only impact. No confidentiality or integrity impact. |
| Affected versions | Go standard library crypto/tls: < go1.25.13, go1.26.0 – go1.26.5, go1.27.0 – go1.27.0-rc.2. All Go binaries compiled with these toolchains inherit the flaw. |
| Fixed versions | go1.25.13, go1.26.6, go1.27.0-rc.3 and later. Distro backports: Ubuntu and Red Hat packages pending evaluation (RHSA-2026:67975 issued). Downstream projects (KrakenD CE 2.13.9, EE 2.13.7) shipping rebuilt binaries. |
| Scanning / exposure | No GreyNoise or Shodan tags specific to this CVE. Go TLS endpoints are not trivially distinguishable from other TLS stacks via passive scanning. JA3/JA4 fingerprinting can identify Go's crypto/tls but requires active probing. |
| Disclosure date | 2026-08-13 (coordinated disclosure via Go security process, golang/go#80528). |
| Credit | Qi Deng of Aurascape.ai. Related sibling CVE: CVE-2026-32283 (TLS 1.3 KeyUpdate deadlock — separate fix, same attack surface). |
Why this verdict
- Availability-only impact ceiling: The CVSS vector confirms C:N/I:N — no data exfiltration, no code execution, no privilege escalation. The worst outcome is temporary service unavailability, which is a lower-consequence outcome than the HIGH label implies.
- TLS-terminating proxy pattern dominates production: The vast majority of Go services in enterprise environments (Kubernetes pods, cloud-hosted APIs, microservices behind service meshes like Istio/Linkerd) sit behind reverse proxies or load balancers that terminate TLS. The Go process never receives raw TLS records, making it immune. Conservative estimate: >70% of Go TLS services in enterprise fleets are shielded this way.
- Connection-scoped, non-persistent DoS: The attacker must maintain active connections to sustain CPU burn. There is no amplification, no persistence, and no lasting damage. Dropping the connections immediately restores service. Standard connection timeouts (60–120s) and concurrency limits bound the blast radius without any patching.
- Low exploitation probability: EPSS 0.57% (44.9th percentile), no KEV listing, no known campaigns, no public weaponized PoC. The attack requires a custom TLS client — it won't be swept up in opportunistic scanning.
- Role multiplier: Go's
crypto/tlsis used in high-value infrastructure: Kubernetes API server, etcd, Vault, Consul, Docker registry, Prometheus. The chain succeeds if these components terminate TLS directly (some Kubernetes API servers do). However, even in the worst case — DoS of a Kubernetes API server — the outcome is *temporary cluster management unavailability*, not domain takeover, fleet compromise, or data exfiltration. This does not meet the HIGH floor threshold of 'domain takeover / fleet compromise / mass data egress / supply-chain pivot.' For etcd and Vault: same analysis — availability disruption, not compromise. The floor does not apply. - Ubuntu independent assessment confirms: Ubuntu's security team independently rated this Medium priority, aligning with our friction analysis rather than the vendor's CVSS label.
Why not higher?
The vendor's HIGH (7.5) would be justified if the majority of Go TLS services were directly exposed to untrusted clients without intermediary TLS termination. In practice, the enterprise deployment pattern (reverse proxy → Go backend) shields most targets. The impact ceiling is availability-only with no path to compromise, which caps the real-world severity below HIGH even for directly-exposed instances.
Why not lower?
Despite the heavy friction, the attack vector is genuinely unauthenticated and low-complexity against directly-exposed Go TLS services. Some Kubernetes API servers, internal mTLS microservices, and standalone Go web servers *do* terminate TLS natively. A motivated attacker with internal network access could selectively DoS critical Go infrastructure components. The breadth of the Go ecosystem means millions of binaries are theoretically affected, and recompilation is the only true fix — there is no runtime configuration toggle to disable TLS 1.3 KeyUpdate processing.
What to do — in priority order.
- Place Go services behind a TLS-terminating reverse proxy — If the Go process doesn't handle raw TLS, this CVE is completely neutralized. Deploy nginx, Envoy, HAProxy, or a cloud LB in front of any directly-exposed Go TLS endpoint. This is the single most effective control and should be prioritized as a noisgate remediation SLA item within the 365-day MEDIUM window, or immediately for any internet-facing Go TLS services.
- Set connection timeouts and concurrency limits — Configure
http.Server.ReadTimeout,WriteTimeout, andIdleTimeout(e.g., 60s each) and usehttp.Server.MaxHeaderBytesorgolang.org/x/net/netutil.LimitListenerto cap concurrent connections. This bounds the CPU burn duration and attacker resource commitment. Deploy within the remediation window. - Upgrade Go toolchain and rebuild affected binaries — Update to go1.25.13+, go1.26.6+, or go1.27.0-rc.3+ and recompile all affected services. This is the definitive fix. For the MEDIUM verdict, the noisgate remediation SLA gives 365 days, but prioritize internet-facing and high-value services (Kubernetes components, API gateways) within 90 days.
- Monitor Go process CPU utilization — Alert on sustained CPU spikes (>90% for >60s) on Go TLS-serving processes via Prometheus, Datadog, or your APM stack. This provides detection-in-depth while patching rolls out. Configure immediately as an observability hygiene item.
- Enforce mTLS where feasible — Requiring client certificates eliminates unauthenticated attackers from the threat model. This is already standard in service meshes (Istio, Linkerd) and Kubernetes internal communication. Verify enforcement on any Go service that terminates TLS directly.
- WAF rules — Web Application Firewalls operate at the HTTP layer (L7) and cannot inspect or filter TLS 1.3 post-handshake records, which are processed before HTTP parsing begins.
- Disabling TLS 1.3 via Go configuration — While
tls.Config.MaxVersion = tls.VersionTLS12would technically prevent TLS 1.3 negotiation, this trades a DoS vulnerability for a cryptographic downgrade and is not recommended as a compensating control. - IP-based rate limiting alone — The attack requires only a small number of connections; IP rate limiting at the connection level won't prevent a slow-and-low variant with a handful of persistent connections from a single source.
Crowdsourced verification payload.
Run this script on any host where Go binaries are deployed or the Go toolchain is installed. Execute as any user with read access to the target binaries: bash check_cve_2026_56862.sh [/path/to/go-binary]. If no argument is given, it checks the system Go toolchain version. No elevated privileges required.
#!/usr/bin/env bash
# check_cve_2026_56862.sh — Detect Go crypto/tls KeyUpdate DoS (CVE-2026-56862)
# Usage: bash check_cve_2026_56862.sh [/path/to/go-binary]
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -euo pipefail
parse_go_version() {
local raw="$1"
# Extract version like go1.25.13 or go1.26.6
local ver
ver=$(echo "$raw" | grep -oP 'go1\.\d+\.\d+' | head -1)
if [[ -z "$ver" ]]; then
ver=$(echo "$raw" | grep -oP 'go1\.\d+' | head -1)
if [[ -n "$ver" ]]; then ver="${ver}.0"; fi
fi
echo "$ver"
}
check_version() {
local ver="$1"
local major minor patch
major=$(echo "$ver" | sed 's/go//' | cut -d. -f1)
minor=$(echo "$ver" | cut -d. -f2)
patch=$(echo "$ver" | cut -d. -f3)
patch=${patch:-0}
# go1.25.x: fixed in 1.25.13
if [[ "$minor" -le 25 ]]; then
if [[ "$minor" -lt 25 ]]; then
echo "VULNERABLE"
elif [[ "$patch" -lt 13 ]]; then
echo "VULNERABLE"
else
echo "PATCHED"
fi
# go1.26.x: fixed in 1.26.6
elif [[ "$minor" -eq 26 ]]; then
if [[ "$patch" -lt 6 ]]; then
echo "VULNERABLE"
else
echo "PATCHED"
fi
# go1.27.x: fixed in 1.27.0-rc.3 (treat any 1.27.0+ release as patched for simplicity)
elif [[ "$minor" -ge 27 ]]; then
echo "PATCHED"
else
echo "UNKNOWN"
fi
}
if [[ $# -ge 1 ]]; then
TARGET="$1"
if [[ ! -f "$TARGET" ]]; then
echo "UNKNOWN — file not found: $TARGET"
exit 2
fi
RAW=$(go version "$TARGET" 2>/dev/null || true)
if [[ -z "$RAW" ]]; then
echo "UNKNOWN — could not determine Go version for $TARGET (not a Go binary or 'go' not in PATH)"
exit 2
fi
else
RAW=$(go version 2>/dev/null || true)
if [[ -z "$RAW" ]]; then
echo "UNKNOWN — Go toolchain not found in PATH"
exit 2
fi
fi
VER=$(parse_go_version "$RAW")
if [[ -z "$VER" ]]; then
echo "UNKNOWN — could not parse Go version from: $RAW"
exit 2
fi
RESULT=$(check_version "$VER")
echo "$RESULT — $RAW (parsed: $VER)"
case "$RESULT" in
PATCHED) exit 0 ;;
VULNERABLE) exit 1 ;;
*) exit 2 ;;
esacWhat defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.