Someone found Go's version of the 2011 Apache Range-header killer, fifteen years later
CVE-2026-78667 is a CPU-exhaustion denial-of-service in Go's standard library net/http package. The functions FileServer, FileServerFS, ServeContent, ServeFile, and ServeFileFS parsed every byte-range in an incoming HTTP Range header without any upper bound. An unauthenticated remote attacker can craft a single HTTP request containing thousands of tiny, overlapping ranges (e.g., Range: bytes=0-0,1-1,2-2,...) and force the server to burn CPU assembling multipart responses for each one. The flaw is tracked as CWE-770 (Allocation of Resources Without Limits or Throttling). All Go versions before 1.26.9 are affected, plus Go 1.27.0 and 1.27.1. The fix (Go 1.26.9 / 1.27.2) caps range count at 200 by default, tunable via GODEBUG=httpservecontentmaxranges=N. Credit goes to researcher Jakub Ciolek.
The vendor CVSS of 7.5 HIGH is *technically* correct — the vector AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H accurately reflects that this is unauthenticated, network-reachable, low-complexity, and causes high availability impact. However, it overstates operational risk for most enterprise fleets. The impact ceiling is availability only — no code execution, no data exfiltration, no privilege escalation. The attack only affects Go binaries that actively serve static content via the specific affected functions; API servers, gRPC endpoints, and custom handlers are untouched. Most production Go services sit behind a reverse proxy or CDN that either strips or limits Range headers. This is the same class of bug Apache fixed in 2011 with CVE-2011-3192 and the MaxRanges directive — well-understood, easily mitigated, and bounded in blast radius. noisgate downgrades this to MEDIUM (5.3).
4 steps from start to impact.
Identify a Go HTTP file-serving endpoint
http.FileServer, http.ServeFile, http.ServeFileFS, or http.ServeContent. These are the only functions affected. The target must be reachable over the network — typically a web application, documentation server, or asset CDN written in Go.- Target runs a Go binary compiled with Go < 1.26.9 or Go 1.27.0-1.27.1
- Target uses one of the four affected file-serving functions
- Endpoint is network-reachable by the attacker
- Many Go services use custom handlers,
gin,echo,chi, or gRPC — none of which call the affected stdlib functions for their core routes - Production Go services frequently sit behind nginx, Caddy, Cloudflare, or an AWS ALB that may strip or reject malformed Range headers
govulncheck (Go's official tool) detects GO-2026-6609 at the call-graph level, confirming whether your binary actually calls the affected functions.Craft a Range header with thousands of small ranges
Range header with thousands of byte-range specs (e.g., Range: bytes=0-0,1-1,2-2,...,9999-9999). No special tooling is needed — curl or a short Python script suffices. The header itself is a single line and fits well within typical HTTP header size limits.- Attacker can send arbitrary HTTP headers to the target
- No WAF or reverse proxy strips or limits the Range header
- Many WAFs (ModSecurity CRS, Cloudflare, AWS WAF) have rules limiting Range header complexity inherited from the CVE-2011-3192 era
- Load balancers may impose header-size limits that cap the number of ranges
Server CPU exhaustion on request processing
multipart/byteranges response. With thousands of ranges on a single request, CPU time per request balloons. The attacker repeats this across multiple connections to saturate all available CPU cores, rendering the service unresponsive to legitimate traffic. Impact is denial of service — the process remains running but starved.- Requests reach the Go process without range-count filtering
- Target file exists and is servable
- CPU exhaustion is per-process; Go's goroutine scheduler means other endpoints on the same binary may still partially respond
- Kubernetes liveness probes or systemd watchdogs may restart the process, limiting sustained outage
- Rate limiting at the load-balancer layer bounds attacker throughput
runtime.NumGoroutine, CPU profile) show hot path in http.ServeContent range parsing.Service degradation or outage
- Attacker sustains traffic volume
- Auto-scaling infrastructure (K8s HPA, cloud ASGs) can absorb load spikes by spawning new pods or instances
- CDN caching means most static file requests never reach origin
max_ranges 1; or strip Range entirely; Envoy: custom Lua filter; Cloudflare/AWS WAF: custom rule rejecting Range headers with >10 ranges). This stops malicious requests before they reach the Go process. Most enterprise deployments already have a proxy tier. Deploy within the noisgate MEDIUM remediation window.govulncheck. Schedule within the noisgate MEDIUM remediation SLA of 365 days.govulncheck) performs call-graph analysis to determine if your code actually invokes the affected functions. This lets you triage which binaries need the GODEBUG workaround or rebuild. Add to CI pipelines immediately to scope the problem.- Rate limiting alone does not fully mitigate — a single request with thousands of ranges can consume significant CPU. You need to limit *range count per request*, not just request rate.
- Disabling HTTP/2 does not help — this vulnerability is in HTTP/1.1 Range header parsing and applies regardless of protocol version.
- Go module pinning (e.g., pinning
net/httpversion) is not applicable —net/httpis part of the Go standard library and is tied to the Go toolchain version, not a separately versioned module.
The supporting signals.
| In-the-Wild Exploitation | None observed. Not listed in CISA KEV. No GreyNoise or Shadowserver tags as of 2026-10-24. No known campaigns. |
|---|---|
| Proof-of-Concept | No public PoC found. pocindex.io has no entry. No dedicated GitHub repos. However, exploitation is trivial — a one-line curl command with a long Range header suffices; no weaponized tooling is needed. |
| EPSS | 0.00379 (~96th percentile low). Indicates very low predicted exploitation probability in the next 30 days. |
| KEV Status | Not listed. No CISA KEV entry as of 2026-10-24. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (7.5 HIGH). Network-reachable, no auth required, availability-only impact. No confidentiality or integrity impact. |
| Affected Versions | Go standard library net/http: all versions before go1.26.9; go1.27.0 through go1.27.1. |
| Fixed Versions | go1.26.9, go1.27.2, and go1.28+. Distro backports: Red Hat issuing RHSA-2026:86093 and RHSA-2026:86196. Debian tracking at security-tracker.debian.org. |
| GODEBUG Workaround | GODEBUG=httpservecontentmaxranges=200 (default in patched versions). Set to any positive integer to cap ranges without recompiling. |
| Disclosure & Credit | Disclosed 2026-10-08 via Go security release. Reported by Jakub Ciolek (ciolek.dev). Go issue #81858. |
| Historical Parallel | Functionally identical to CVE-2011-3192 (Apache httpd Range header DoS), which was actively exploited in August 2011 and led to Apache's MaxRanges directive. The Go ecosystem was 15 years late adding the same safeguard. |
Sources.
- Go Vulnerability Database — GO-2026-6609
- Go Issue #81858 — Range header limit
- Go Security Release Announcement (golang-announce)
- oss-security — Go 1.27.2 and 1.26.9 release
- Red Hat CVE Page — CVE-2026-78667
- Debian Security Tracker — CVE-2026-78667
- KrakenD Security Advisory — CVE-2026-78667
- CVE-2011-3192 — Apache Range Header DoS (historical parallel)
Why this verdict
- Availability-only impact ceiling: The attack can only cause CPU exhaustion — no code execution, no data exfiltration, no privilege escalation. The CVSS C:N/I:N confirms this. For a fleet manager, a DoS-only bug competes for attention against RCE and auth-bypass vulns that actually compromise hosts.
- Narrow function surface: Only Go binaries calling
FileServer,ServeFile,ServeFileFS, orServeContentare vulnerable. Most production Go services use framework routers (gin,echo,chi) or gRPC for their core APIs. The file-serving stdlib functions are typically used for admin UIs, documentation, or static asset fallbacks — a fraction of the Go binary population. - Reverse-proxy friction compresses real-world reachability: The majority of enterprise Go services sit behind nginx, Envoy, Caddy, Cloudflare, or a cloud ALB. Many of these already limit Range header complexity (a lesson learned from CVE-2011-3192 in 2011). Requests with thousands of ranges are likely rejected before reaching the Go process.
- Trivial runtime workaround without recompile: Setting
GODEBUG=httpservecontentmaxranges=200on any running Go binary immediately caps range parsing. No code change, no rebuild, no restart of dependent services. This is a rare luxury for a stdlib vuln. - Role multiplier: Go
net/httpis embedded in high-value components (Kubernetes kubelet/apiserver, Docker/containerd, HashiCorp Vault, Consul). However, these components overwhelmingly use custom HTTP handlers, gRPC, or internal transport — notFileServer/ServeContentfor their critical paths. The realistic blast radius on a Kubernetes control plane node is limited to optional static-file endpoints (e.g.,/swagger-ui), not the API surface itself. Impact remains DoS of a non-critical sub-endpoint, not fleet compromise or domain takeover. The high-value-role floor (HIGH) does not engage because the outcome never reaches domain takeover, fleet compromise, mass data egress, supply-chain pivot, or OT-safety impact — it stays at service-level availability degradation. - No exploitation signal: EPSS 0.00379, no KEV listing, no GreyNoise tags, no public PoC repos. The attack is trivial to construct but nobody is bothering — DoS bugs in file-serving endpoints are low-value targets for real adversaries.
Why not higher?
Upgrading to HIGH would require either a path to code execution, data compromise, or evidence that high-value infrastructure components (identity, hypervisor, CI/CD) call the affected functions in their critical serving paths. None of these conditions hold. The impact ceiling is availability-only against a narrow subset of Go functions. Even in the worst case — a Go-based CDN origin serving static assets — the outcome is a recoverable service outage, not a compromise. No exploitation in the wild further weakens the case for HIGH.
Why not lower?
Dropping to LOW would understate the ease of exploitation. This is unauthenticated, network-reachable, low-complexity, and requires no user interaction — the four attributes that make DoS bugs operationally annoying. Go is the dominant language for cloud-native infrastructure, so the potential target population is large even if the specific function surface is narrow. The historical parallel with CVE-2011-3192 (which *was* actively exploited) and the fact that no prior range-count limit existed in Go's 14-year history of net/http means some environments will have exposed, unproxied Go file servers. MEDIUM correctly reflects a bug that deserves scheduled patching, not emergency response.
Crowdsourced verification payload.
Run this script on any host where Go is installed (build servers, CI agents, container base images). Invoke as bash check_cve_2026_78667.sh. Requires go in PATH. No elevated privileges needed. Outputs VULNERABLE, PATCHED, or UNKNOWN with exit codes 1, 0, 2 respectively.
#!/usr/bin/env bash
# CVE-2026-78667 — Go net/http Range Header CPU Exhaustion Detector
# Checks the installed Go toolchain version against known-affected ranges.
# Exit codes: 0=PATCHED 1=VULNERABLE 2=UNKNOWN
set -euo pipefail
VULN="CVE-2026-78667"
if ! command -v go &>/dev/null; then
echo "[$VULN] 'go' not found in PATH"
echo "[$VULN] STATUS: UNKNOWN"
exit 2
fi
RAW=$(go version 2>&1)
if ! VER=$(echo "$RAW" | grep -oP 'go\K[0-9]+\.[0-9]+(\.[0-9]+)?'); then
echo "[$VULN] Could not parse version from: $RAW"
echo "[$VULN] STATUS: UNKNOWN"
exit 2
fi
MAJOR=$(echo "$VER" | cut -d. -f1)
MINOR=$(echo "$VER" | cut -d. -f2)
PATCH=$(echo "$VER" | cut -d. -f3)
PATCH=${PATCH:-0}
echo "[$VULN] Go version: $VER (major=$MAJOR minor=$MINOR patch=$PATCH)"
STATUS="UNKNOWN"
if [[ "$MAJOR" -eq 1 ]]; then
if [[ "$MINOR" -lt 26 ]]; then
STATUS="VULNERABLE"
elif [[ "$MINOR" -eq 26 ]]; then
[[ "$PATCH" -lt 9 ]] && STATUS="VULNERABLE" || STATUS="PATCHED"
elif [[ "$MINOR" -eq 27 ]]; then
[[ "$PATCH" -lt 2 ]] && STATUS="VULNERABLE" || STATUS="PATCHED"
else
STATUS="PATCHED"
fi
fi
# Check for GODEBUG workaround
if [[ "$STATUS" == "VULNERABLE" && -n "${GODEBUG:-}" ]]; then
if echo "$GODEBUG" | grep -qP 'httpservecontentmaxranges=[1-9]'; then
MR=$(echo "$GODEBUG" | grep -oP 'httpservecontentmaxranges=\K[0-9]+')
echo "[$VULN] GODEBUG workaround active: httpservecontentmaxranges=$MR"
STATUS="PATCHED"
fi
fi
echo "[$VULN] STATUS: $STATUS"
case "$STATUS" in
VULNERABLE) exit 1 ;;
PATCHED) exit 0 ;;
*) exit 2 ;;
esac