← Back to Feed CACHED · 2026-10-24 12:49:31 · CACHE_KEY CVE-2026-78667
CVE-2026-78667 · CWE-770 · Disclosed 2026-10-08

Go net/http FileServer CPU exhaustion via unbounded Range header parsing

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

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).

"Go Range header DoS is real but availability-only; reverse proxies and GODEBUG blunt it"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a Go HTTP file-serving endpoint

The attacker identifies a target endpoint that serves static files using Go's 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.
Conditions required:
  • 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
Where this breaks in practice:
  • 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
Detection/coverage: Qualys QID and Tenable plugins for Go version detection exist. govulncheck (Go's official tool) detects GO-2026-6609 at the call-graph level, confirming whether your binary actually calls the affected functions.
STEP 02

Craft a Range header with thousands of small ranges

The attacker constructs an HTTP GET request targeting a static file on the endpoint, appending a 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.
Conditions required:
  • Attacker can send arbitrary HTTP headers to the target
  • No WAF or reverse proxy strips or limits the Range header
Where this breaks in practice:
  • 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
Detection/coverage: WAF logs showing unusually large Range headers. IDS signatures for CVE-2011-3192-style attacks may partially match.
STEP 03

Server CPU exhaustion on request processing

The Go HTTP handler parses every range and begins assembling a 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.
Conditions required:
  • Requests reach the Go process without range-count filtering
  • Target file exists and is servable
Where this breaks in practice:
  • 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
Detection/coverage: Spike in CPU usage correlated with HTTP 206 responses. Go runtime metrics (runtime.NumGoroutine, CPU profile) show hot path in http.ServeContent range parsing.
STEP 04

Service degradation or outage

Sustained attack traffic causes the Go process to consume 100% CPU. Legitimate users experience timeouts or connection refusals. The impact is bounded to availability of the file-serving function — no memory corruption, no code execution, no data leak. Stopping the attack traffic allows immediate recovery.
Conditions required:
  • Attacker sustains traffic volume
Where this breaks in practice:
  • 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
Detection/coverage: Standard availability monitoring (HTTP 5xx rate, latency percentiles, pod restart counts) catches the symptom immediately.
03 · Compensating Control

1
MEDIUM 5.3→IGNORE 0.0
SEVERITY REDUCED
Set GODEBUG=httpservecontentmaxranges=200 on all Go processes — This runtime flag caps the number of parsed ranges at 200, matching the patched default. It requires no code change or recompilation — just set the environment variable and restart the process. Apply to all Go binaries serving static content. This is the fastest mitigation and should be deployed within the noisgate MEDIUM remediation window (365 days), though given the simplicity, there is no reason not to do it this week.
2
MEDIUM 5.3→IGNORE 0.0
SEVERITY REDUCED
Enforce Range header limits at the reverse proxy or WAF — Configure your reverse proxy (nginx: 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.
3
MEDIUM 5.3→IGNORE 0.0
SEVERITY REDUCED
Upgrade Go toolchain to 1.26.9+ or 1.27.2+ — The definitive fix. Rebuild affected binaries with the patched Go toolchain. Prioritize binaries confirmed vulnerable via govulncheck. Schedule within the noisgate MEDIUM remediation SLA of 365 days.
4
MEDIUM 5.3→MEDIUM 5.3
Run govulncheck in CI/CD to identify affected binaries — Go's official vulnerability scanner (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.
What doesn't work
  • 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/http version) is not applicable — net/http is part of the Go standard library and is tied to the Go toolchain version, not a separately versioned module.
04 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNone observed. Not listed in CISA KEV. No GreyNoise or Shadowserver tags as of 2026-10-24. No known campaigns.
Proof-of-ConceptNo 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.
EPSS0.00379 (~96th percentile low). Indicates very low predicted exploitation probability in the next 30 days.
KEV StatusNot listed. No CISA KEV entry as of 2026-10-24.
CVSS VectorCVSS: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 VersionsGo standard library net/http: all versions before go1.26.9; go1.27.0 through go1.27.1.
Fixed Versionsgo1.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 WorkaroundGODEBUG=httpservecontentmaxranges=200 (default in patched versions). Set to any positive integer to cap ranges without recompiling.
Disclosure & CreditDisclosed 2026-10-08 via Go security release. Reported by Jakub Ciolek (ciolek.dev). Go issue #81858.
Historical ParallelFunctionally 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.

  1. Go Vulnerability Database — GO-2026-6609
  2. Go Issue #81858 — Range header limit
  3. Go Security Release Announcement (golang-announce)
  4. oss-security — Go 1.27.2 and 1.26.9 release
  5. Red Hat CVE Page — CVE-2026-78667
  6. Debian Security Tracker — CVE-2026-78667
  7. KrakenD Security Advisory — CVE-2026-78667
  8. CVE-2011-3192 — Apache Range Header DoS (historical parallel)
05 · The Call

Final Verdict
↓ DOWNGRADED to MEDIUM (5.3/10)

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, or ServeContent are 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=200 on 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/http is 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 — not FileServer/ServeContent for 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.

06 · Verification

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.

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