Like a zip bomb hidden in a breadcrumb trail — every '..' makes the parser re-walk the entire path
CVE-2026-56860 is a denial-of-service flaw in Go's standard library net/url package, specifically in the resolvePath function called by URL.Parse and URL.ResolveReference. When processing relative URL paths containing parent-directory (..) segments, the old implementation performed a full string conversion and buffer rewrite at every step, producing O(n²) time complexity and proportionally bloated memory allocations. An attacker who can feed a crafted URL with a long chain of .. segments into a Go service can spike CPU and heap usage on that process. Affected versions: Go < 1.25.13, Go 1.26.0 through 1.26.5, and Go 1.27.0-rc.1/rc.2. Fixed in Go 1.25.13, 1.26.6, and 1.27.0-rc.3.
The vendor's MEDIUM / 5.9 rating is directionally correct but slightly generous. The CVSS vector (AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H) already captures the high attack complexity and availability-only impact. In practice, several additional friction layers — HTTP URL-length ceilings, Go's goroutine-per-request model that isolates slow parsing to a single goroutine, the need for sustained concurrent malicious requests to actually degrade service, and the total absence of public PoC code or in-the-wild exploitation — all compound to make the real-world risk incrementally lower than what the raw CVSS communicates. A 4.8 better reflects the actual threat to a managed fleet.
4 steps from start to impact.
Identify a Go-based network service
Server, TLS fingerprinting with JARM) or known product stacks (Caddy, Traefik, custom APIs). No tooling beyond standard recon is required.- Target runs a Go binary compiled with a vulnerable Go toolchain
- Service is network-reachable
- Go version is not typically disclosed in HTTP headers
- Many Go services sit behind a CDN or reverse proxy that masks origin
go version -m <binary> on the host. Network-side: TLS JARM fingerprinting can identify Go HTTP servers.Craft a URL with deeply nested '..' segments
/../ segments, e.g. /a/../a/../a/../... repeated thousands of times. The goal is to maximize the number of iterations through resolvePath. The crafted URL must be a valid HTTP request that the Go service will parse. No specialized tooling is needed — curl or python requests suffices.- Attacker can send arbitrary HTTP requests to the service
- Go's
net/httpserver enforcesMaxHeaderBytes(default 1 MB) which caps request-line length - Many WAFs and load balancers impose their own URL length limits (e.g. Cloudflare: 32 KB, AWS ALB: 8 KB)
- URL normalization at the proxy layer may strip
..segments before they reach the Go process
.. in URL path. Log analysis for abnormally long request URIs.Trigger URL.Parse or URL.ResolveReference on untrusted input
url.URL.Parse or url.URL.ResolveReference, which internally invokes resolvePath. The Go HTTP server's request parsing calls url.Parse on the request URL, so standard HTTP handlers may be affected. However, the specific resolvePath logic is invoked only when the path actually contains .. segments and requires resolution — not on every URL parse.- Application processes the URL through a code path that invokes resolvePath
- The .. segments survive any upstream normalization
- Go's HTTP server may clean/reject the path before handler dispatch depending on mux configuration
- Applications using
http.ServeMuxgetpath.Cleanapplied, which may not trigger resolvePath - The CVSS AC:H reflects that not all Go HTTP services trigger the vulnerable code path
govulncheck to identify whether the application's call graph reaches the affected url.URL.Parse or url.URL.ResolveReference symbols.Sustain concurrent requests to exhaust resources
- Attacker can sustain high-volume requests
- No rate limiting or connection throttling in place
- Rate limiting at CDN/LB/WAF layer stops volume-based DoS
- Go's goroutine scheduler and GC recover gracefully under moderate load
- Kubernetes HPA or similar autoscaling can absorb burst CPU spikes
- Standard DDoS mitigation (Cloudflare, AWS Shield) applies
The supporting signals.
| In-the-wild exploitation | None observed. Not listed in CISA KEV. No campaigns or threat actor usage reported as of 2026-09-20. |
|---|---|
| Proof of concept | No public PoC. The Go issue #80494 was reported by *jitsu-net* on 2026-07-21 and handled under Go's security process. No exploit code has been published. |
| EPSS | 0.00518 (0.52%) — bottom quartile. The model rates exploitation probability as very low over the next 30 days. |
| KEV status | Not listed. No CISA KEV entry as of 2026-09-20. |
| CVSS vector | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H — Network-accessible, high complexity, no privs needed, availability-only impact. The AC:H is the key limiter: not every Go service triggers resolvePath on untrusted input. |
| Affected versions | Go < 1.25.13, Go 1.26.0 through 1.26.5, Go 1.27.0-rc.1 through 1.27.0-rc.2 |
| Fixed versions | Go 1.25.13, 1.26.6, 1.27.0-rc.3+. Distro backports: RHSA-2026:65886 (RHEL), RHSA-2026:67975, RHSA-2026:68527. |
| Affected symbols | url.URL.Parse, url.URL.ResolveReference → internal resolvePath function |
| Scanning / exposure | No Shodan/GreyNoise/Censys data specific to this CVE. Go HTTP services are identifiable via JARM TLS fingerprinting but the vulnerability requires application-level analysis (govulncheck), not network scanning. |
| Reporter | jitsu-net via Go security process. Tracked as GO-2026-6218, GHSA-25mv-j2qr-v5jq. |
Why this verdict
- No exploitation evidence or PoC: Zero in-the-wild activity, no KEV listing, no public exploit code. EPSS at 0.52% puts this in the bottom quartile. There is nothing to chase right now.
- AC:H is real friction, not theoretical: The
resolvePathcode path is only invoked when URL paths contain..segments *and* pass throughURL.ParseorURL.ResolveReference. Go's standardhttp.ServeMuxappliespath.Cleanbefore dispatch, and many reverse proxies normalize paths upstream, meaning the vulnerable code path is not universally reachable on every Go HTTP endpoint. - Availability-only impact with natural throttling: Even when triggered, the quadratic blowup is confined to a single goroutine. Go's concurrency model, runtime GC, and typical deployment patterns (load balancer, rate limiting, autoscaling) all limit the blast radius of a single crafted request. Sustained concurrent volume is required for service-level impact, which crosses into generic DDoS territory where existing mitigations apply.
- URL length ceilings cap the payload: Go's
net/httpenforces a defaultMaxHeaderBytesof 1 MB, and upstream proxies (Cloudflare 32 KB, AWS ALB 8 KB) impose tighter limits. The quadratic factor is bounded by input length, so the worst-case CPU spike is architecturally capped. - Role multiplier: Go's
net/urlis used in high-value components — Kubernetes API server, Docker/containerd, HashiCorp Vault, Traefik, Caddy, Prometheus. The chain *can* succeed against these if an attacker reaches them with crafted URLs. However, the outcome is always service-level DoS (one process, recoverable), never domain takeover, fleet compromise, data exfiltration, or supply-chain pivot. Kubernetes API servers require authentication for most endpoints; Vault requires tokens; network proxies are typically behind DDoS mitigation. The blast radius is host-level at worst, goroutine-level typically. This does not meet the HIGH floor threshold because no high-value role outcome reaches 'domain takeover / fleet compromise / mass data egress / supply-chain pivot.'
Why not higher?
The vulnerability produces availability impact only — no path to code execution, privilege escalation, data disclosure, or lateral movement. The outcome ceiling is transient service degradation on a single Go process, not domain compromise or fleet-scale impact. The attack requires sustained concurrent malicious requests, making it operationally equivalent to a generic application-layer DDoS rather than a precise exploit chain. No PoC or exploitation evidence exists to justify urgency.
Why not lower?
Go is the dominant language for cloud-native infrastructure. The net/url package is nearly universal in Go codebases, and while the specific resolvePath trigger requires .. segments, the sheer number of Go services processing untrusted URLs means the addressable attack surface is non-trivial. The flaw is unauthenticated and network-reachable, and a determined attacker targeting a specific high-value Go service (e.g., an unprotected API gateway) could cause meaningful disruption. Dropping below MEDIUM would understate the risk to unshielded deployments.
What to do — in priority order.
- Run govulncheck across your Go module inventory — Use
govulncheck ./...in each Go module to determine whether your application's call graph actually reaches the vulnerableurl.URL.Parseorurl.URL.ResolveReferencesymbols. If govulncheck reports no reachable usage, the binary is not exploitable regardless of Go version. This triage step eliminates false positives and focuses patching effort. No mitigation SLA applies for MEDIUM — go straight to the 365-day remediation window. - Enforce URL length limits at the edge — Configure your reverse proxy, WAF, or load balancer to reject request URLs exceeding a reasonable length (e.g. 8 KB). This caps the quadratic blowup factor and neutralizes the DoS potential. Most production deployments already have this in place. Apply within the 365-day remediation window.
- Normalize paths at the proxy layer — Enable path normalization (resolve
..segments) at your reverse proxy (nginxmerge_slashes, Envoy path normalization, Cloudflare URL rewriting). This strips the malicious..chains before they reach Go, eliminating the trigger entirely. - Rebuild and redeploy with Go ≥ 1.25.13 / 1.26.6 — The definitive fix is recompiling your Go binaries with a patched Go toolchain. Prioritize services that are internet-facing and process untrusted URLs. Target completion within the noisgate 365-day remediation SLA for MEDIUM severity.
- Enable rate limiting on URL-processing endpoints — Apply per-client rate limiting at the application or proxy level to prevent the sustained concurrent requests needed to escalate a single-goroutine slowdown into service-level DoS.
- Input validation on
..in application code — by the time your handler sees the request, Go's HTTP server has already parsed the URL viaurl.Parse, which is where the vulnerability triggers. Validating the path in your handler is too late. - Upgrading only the Go binary without recompiling — Go statically links the standard library. You must recompile your application with the patched Go toolchain; simply updating the
gocommand on the host does nothing for already-deployed binaries. - Generic network-level DDoS protection alone — while DDoS mitigation helps with the volume component, a single well-crafted request with a long
..chain can still cause a CPU spike in one goroutine. The algorithmic fix in the Go runtime is the only complete remediation.
Crowdsourced verification payload.
Run this script on any host where Go binaries are deployed. It checks the Go toolchain version and optionally scans specified binaries for their embedded Go version. Requires go in PATH for toolchain check, or pass binary paths as arguments. No elevated privileges needed. Example: bash check_cve_2026_56860.sh /usr/local/bin/myservice /usr/bin/kubectl
#!/usr/bin/env bash
# check_cve_2026_56860.sh — Detect Go net/url quadratic path resolution DoS
# CVE-2026-56860 | GO-2026-6218
# Affected: Go < 1.25.13, Go 1.26.0-1.26.5, Go 1.27.0-rc.1/rc.2
# Fixed: Go 1.25.13+, Go 1.26.6+, Go 1.27.0-rc.3+
# Usage: bash check_cve_2026_56860.sh [binary1 binary2 ...]
# Output: VULNERABLE / PATCHED / UNKNOWN
set -euo pipefail
VULNERABLE=0
PATCHED=0
UNKNOWN=0
check_version() {
local label="$1"
local ver="$2"
# Strip 'go' prefix if present
ver="${ver#go}"
# Extract major.minor.patch
local major minor patch
IFS='.' read -r major minor patch <<< "$(echo "$ver" | sed 's/-.*//; s/rc.*//')"
patch="${patch:-0}"
local rc=""
if [[ "$ver" == *"-rc."* ]]; then
rc="$(echo "$ver" | grep -oP 'rc\.\K[0-9]+')"
elif [[ "$ver" == *"rc"* ]]; then
rc="$(echo "$ver" | grep -oP 'rc\K[0-9]+')"
fi
local result="UNKNOWN"
if [[ "$major" -eq 1 ]]; then
if [[ "$minor" -le 24 ]]; then
# Go 1.24 and earlier — not in affected range per advisory (affected starts 1.25.0)
result="PATCHED" # Not in affected version range
elif [[ "$minor" -eq 25 ]]; then
if [[ "$patch" -ge 13 ]]; then
result="PATCHED"
else
result="VULNERABLE"
fi
elif [[ "$minor" -eq 26 ]]; then
if [[ "$patch" -ge 6 ]]; then
result="PATCHED"
else
result="VULNERABLE"
fi
elif [[ "$minor" -eq 27 ]]; then
if [[ -n "$rc" ]]; then
if [[ "$rc" -ge 3 ]]; then
result="PATCHED"
else
result="VULNERABLE"
fi
elif [[ "$patch" -ge 0 ]]; then
result="PATCHED" # 1.27.0 release or later
fi
elif [[ "$minor" -gt 27 ]]; then
result="PATCHED"
fi
fi
echo "[$result] $label: go$ver"
case "$result" in
VULNERABLE) VULNERABLE=$((VULNERABLE + 1)) ;;
PATCHED) PATCHED=$((PATCHED + 1)) ;;
*) UNKNOWN=$((UNKNOWN + 1)) ;;
esac
}
# Check installed Go toolchain
if command -v go &>/dev/null; then
toolchain_ver="$(go version | awk '{print $3}')"
check_version "Go toolchain" "$toolchain_ver"
else
echo "[INFO] Go toolchain not found in PATH"
fi
# Check specified binaries
for bin in "$@"; do
if [[ ! -f "$bin" ]]; then
echo "[UNKNOWN] $bin: file not found"
UNKNOWN=$((UNKNOWN + 1))
continue
fi
bin_ver="$(go version -m "$bin" 2>/dev/null | head -1 | awk '{print $2}' || true)"
if [[ -z "$bin_ver" ]]; then
echo "[UNKNOWN] $bin: not a Go binary or version unreadable"
UNKNOWN=$((UNKNOWN + 1))
continue
fi
check_version "$bin" "$bin_ver"
done
# Summary
echo ""
echo "=== CVE-2026-56860 Scan Summary ==="
echo "VULNERABLE: $VULNERABLE | PATCHED: $PATCHED | UNKNOWN: $UNKNOWN"
if [[ $VULNERABLE -gt 0 ]]; then
echo "VULNERABLE"
exit 1
elif [[ $UNKNOWN -gt 0 && $PATCHED -eq 0 ]]; then
echo "UNKNOWN"
exit 2
else
echo "PATCHED"
exit 0
fiWhat defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.