← Back to Feed CACHED · 2026-09-20 10:45:42 · CACHE_KEY CVE-2026-84445
CVE-2026-84445 · CWE-129 · Disclosed 2026-09-14

gRPC-Go is the Go language implementation of gRPC.

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

A bouncer who lets everyone in but faints when someone doesn't show ID

CVE-2026-84445 is an index-out-of-bounds panic in gRPC-Go's xDS server routing interceptor. When a server is created via xds.NewGRPCServer(), every inbound RPC passes through a routing interceptor that looks up the :authority pseudo-header to select a virtual host. If a crafted HTTP/2 request arrives with *neither* the :authority header nor the Host header, the interceptor tries to read the first element of an empty slice — Go panics, and because the per-RPC goroutine has no recover(), the entire server process terminates. All versions of google.golang.org/grpc before 1.82.2, and the 1.83.0–1.83.1 range, are affected. The fix landed in 1.82.2 and 1.83.2. Crucially, only servers instantiated with xds.NewGRPCServer() are vulnerable; the standard grpc.NewServer() path — which represents the vast majority of grpc-go deployments — is completely unaffected.

Third-party CVSS 4.0 assessments peg this at 8.7 (HIGH), and the GitHub Security Advisory from grpc/grpc-go labels it High. That rating accurately reflects the raw mechanics: network-reachable, no authentication required (in non-mTLS configs), zero user interaction, full availability impact from a single packet. But it overweights the theoretical population. The xDS server API is a proxyless service-mesh feature used by teams running Istio proxyless gRPC, Google Traffic Director, or custom xDS control planes — a small fraction of the enormous grpc-go install base. The majority of those xDS deployments live inside Kubernetes clusters behind load balancers with mTLS enabled, which blocks unauthenticated exploitation entirely. The impact ceiling is DoS — no data exfiltration, no code execution, no lateral movement. Kubernetes auto-restarts crashed pods, limiting sustained outage. A MEDIUM assessment better reflects the real-world exploitability and blast radius.

"xDS-only DoS in grpc-go: one headerless request kills the server, but most deployments aren't running xDS"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Locate an xDS-enabled gRPC endpoint

The attacker identifies a gRPC service using xds.NewGRPCServer() rather than standard grpc.NewServer(). This can be inferred from service mesh configurations, bootstrap files referencing an xDS management server, or by observing xDS-specific metadata in gRPC reflection responses. Scanning tools like grpcurl can enumerate exposed gRPC services.
Conditions required:
  • Target runs gRPC-Go server instantiated via xds.NewGRPCServer()
  • Attacker has network reachability to the gRPC port (typically internal)
Where this breaks in practice:
  • The vast majority of grpc-go deployments use grpc.NewServer(), not xds.NewGRPCServer()
  • xDS servers typically run inside Kubernetes clusters, not exposed to the internet
  • Differentiating xDS from standard gRPC externally is non-trivial
Detection/coverage: Network scanning tools (nmap, grpcurl) can identify gRPC services but cannot reliably distinguish xDS from standard servers externally.
STEP 02

Complete HTTP/2 transport handshake

The attacker establishes a TCP connection and completes the HTTP/2 connection preface and SETTINGS exchange. If the server uses plaintext or standard TLS, this requires no credentials. If the server uses mTLS or ALTS, the attacker must present a valid client certificate or ALTS identity — a significant barrier in production service mesh deployments.
Conditions required:
  • TCP reachability to the gRPC port
  • For mTLS/ALTS: possession of valid transport credentials
Where this breaks in practice:
  • Production xDS deployments increasingly default to mTLS via Istio/Traffic Director
  • ALTS (Google's Application Layer Transport Security) is common in GCP deployments
  • Network policies and Kubernetes NetworkPolicy objects may restrict pod-to-pod connectivity
Detection/coverage: TLS handshake failures and unauthorized connection attempts are logged by most service mesh telemetry (Istio access logs, Envoy stats).
STEP 03

Send malformed RPC without :authority or Host

The attacker sends an HTTP/2 HEADERS frame initiating an RPC stream that deliberately omits both the :authority pseudo-header and the Host header. Standard HTTP/2 clients and libraries typically auto-populate :authority, so the attacker needs a raw HTTP/2 framing tool like h2c, hyper (Rust), or a custom Go http2 client to craft the malformed frame. No specialized exploit toolkit is required — a ~20-line script suffices.
Conditions required:
  • Established HTTP/2 connection to the target
  • Ability to send raw HTTP/2 frames (bypass client-side :authority auto-population)
Where this breaks in practice:
  • Standard gRPC client libraries auto-populate :authority, so exploitation requires non-standard tooling
  • Compliant HTTP/2 intermediaries (L7 load balancers, Envoy sidecars) may reject or rewrite requests missing :authority before they reach the server
Detection/coverage: HTTP/2 frames missing :authority can be logged by L7 proxies (Envoy, nginx) if access logging is enabled. However, the gRPC server itself does not log the malformed request before crashing.
STEP 04

Server process panics and terminates

The xDS routing interceptor in internal/xds/server/routing.go calls RouteAndProcess, which indexes authorities[0] on an empty slice. Go's runtime raises an index-out-of-bounds panic. Because the interceptor runs in the per-RPC goroutine without a recover() wrapper, the panic propagates to the server's main goroutine and terminates the entire OS process — not just the offending connection. All active RPCs on all connections are killed simultaneously.
Conditions required:
  • Malformed RPC reaches the xDS routing interceptor
Where this breaks in practice:
  • Kubernetes liveness probes will detect the crash and restart the pod, typically within seconds
  • CrashLoopBackOff exponential backoff limits sustained restart frequency after repeated crashes
  • Service mesh health checks will remove the crashed instance from load balancing pools
Detection/coverage: Pod crash events are visible in Kubernetes events (kubectl get events), container runtime logs, and monitoring systems (Prometheus kube_pod_container_status_restarts_total). Crash stack traces appear in stderr/container logs with the runtime error: index out of range signature.
03 · Intelligence Metadata

The supporting signals.

In-the-Wild ExploitationNo known exploitation. Not listed in CISA KEV. No reports of active campaigns targeting this CVE as of 2026-09-20.
Proof-of-ConceptNo public PoC repository identified, but the attack is trivially reproducible with any raw HTTP/2 framing tool (~20 lines of Go or Python). The fix commit itself serves as a de facto PoC guide. Reported by @matiasinsaurralde.
EPSS0.00685 (0.685%) — 49th percentile. Below the median exploitation probability, consistent with a niche-scoped DoS bug.
KEV StatusNot listed. No CISA KEV entry. No BOD 22-01 deadline applies.
CVSSCVSS 4.0: 8.7 (third-party assessment) — CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N. Equivalent CVSS 3.1 base: ~7.5. Reflects unauthenticated network DoS with no C/I impact.
Affected Versionsgoogle.golang.org/grpc < 1.82.2 and >= 1.83.0, < 1.83.2. Only servers using xds.NewGRPCServer() are reachable.
Fixed Versionsv1.82.2 and v1.83.2. Dev branch fix: v1.85.0-dev.0.20260825072537-93e31b48545e. Go vuln ID: GO-2026-6443.
Exposure DatagRPC services are predominantly internal. Shodan/Censys show limited public gRPC exposure; xDS-mode servers are a further subset. KrakenD confirmed unaffected as it does not use xDS. Grafana, Agentcy OIDC Gateway issued dependency updates as precautionary measures.
Disclosure Date2026-09-14 (GHSA published). Go vuln database entry: 2026-09-15.
Reporter@matiasinsaurralde via GitHub Security Advisory GHSA-2v4p-qf9q-27wj.
04 · The Call

Final Verdict
DOWNGRADED to MEDIUM (5.5/10)

Why this verdict

  • xDS-only scope eliminates most of the install base: Only servers created with xds.NewGRPCServer() are affected. Standard grpc.NewServer() — the path used by the overwhelming majority of grpc-go consumers — is completely immune. This narrows the vulnerable population to an estimated 5–15% of grpc-go deployments (those using Istio proxyless, Traffic Director, or custom xDS control planes).
  • DoS ceiling caps severity: The impact is strictly availability. No memory corruption, no code execution, no data leakage. A single malformed request kills the process, but it cannot be chained into lateral movement, privilege escalation, or data exfiltration. This caps the theoretical maximum below HIGH for most deployment contexts.
  • Internal deployment norm limits reachability: xDS-enabled gRPC servers are almost exclusively deployed inside Kubernetes clusters, behind L7 load balancers and service meshes. Direct internet exposure is atypical. An external attacker must first achieve internal network access (post-initial-access), which is a compounding prerequisite that depresses real-world exploitability.
  • mTLS friction blocks the unauthenticated path: Production service mesh deployments using Istio, Traffic Director, or ALTS default to mutual TLS. In mTLS configurations, the attacker must possess valid client certificates to complete the transport handshake — transforming this from an unauthenticated to an authenticated-insider bug. Only insecure/plaintext or one-way TLS deployments are unauthenticated targets.
  • Kubernetes auto-restart limits sustained impact: Crashed pods restart automatically via kubelet. While repeated exploitation can force CrashLoopBackOff, the exponential backoff and service mesh health-check ejection limit the blast radius of sustained DoS. Most clusters recover within seconds of a single crash.
  • Role multiplier: gRPC-Go xDS servers can occupy high-value roles: service mesh data planes handling internal routing, API gateway tiers, or control-plane adjacencies. In such roles, a crash disrupts request routing for dependent services — blast radius is *service tier* to *cluster segment*. However, the impact ceiling is availability degradation, NOT domain takeover, fleet compromise, data exfiltration, or supply-chain pivot. No plausible high-value-role outcome reaches the HIGH-floor threshold because the bug produces only a process crash with no follow-on compromise capability. The component (grpc-go xDS server mode) is not canonically a DC, IdP, CA, backup system, or network edge appliance — it is an application-layer transport library used in microservices.

Why not higher?

The bug is DoS-only with no path to code execution, data theft, or lateral movement. The affected population is narrowed to the xDS subset of grpc-go users (~5–15% of deployments), and within that subset, mTLS — the production default in service mesh environments — blocks unauthenticated exploitation. Kubernetes auto-restart further caps the real-world outage window. No high-value-role scenario produces domain/fleet/supply-chain-scale compromise; the worst case is temporary service disruption in one tier.

Why not lower?

Within the affected xDS population, exploitation is trivially easy: a single unauthenticated HTTP/2 frame in non-mTLS configs kills the entire server process — no special tooling, no race condition, no user interaction. No vendor workaround exists short of upgrading. The EPSS of 0.685% (49th percentile) is non-negligible, and the Go vuln database has cataloged it (GO-2026-6443), ensuring wide scanner coverage. The attack is deterministic and repeatable, making it viable for targeted disruption even if not for broad exploitation.

05 · Compensating Control

What to do — in priority order.

  1. Upgrade grpc-go to v1.82.2 or v1.83.2 — The definitive fix. Both patch versions reject requests missing :authority and Host at the HTTP/2 transport layer before they reach the xDS routing interceptor. Per the noisgate remediation SLA for MEDIUM, deploy within 365 days. If you actively use xds.NewGRPCServer() in production, prioritize this within weeks — the upgrade is a drop-in dependency bump with no API changes.
  2. Enable mTLS or ALTS on all xDS-enabled gRPC servers — mTLS requires valid client certificates before the transport handshake completes, blocking unauthenticated exploitation entirely. Istio and Traffic Director support mTLS as a mesh-wide policy (PeerAuthentication in STRICT mode). This should be your default posture regardless of this CVE. No mitigation SLA applies for MEDIUM severity — go straight to the remediation window.
  3. Deploy an L7 proxy or Envoy sidecar in front of xDS servers — A compliant HTTP/2 intermediary (Envoy, nginx, HAProxy) can validate or inject the :authority header before traffic reaches the gRPC server. Envoy's http2_protocol_options and HTTP connection manager will typically reject or normalize requests missing :authority, acting as a pre-filter. If you're using Istio with sidecars alongside proxyless gRPC, ensure the sidecar is the ingress point.
  4. Configure Kubernetes liveness probes and PodDisruptionBudgets — Ensure liveness probes detect crashed gRPC servers and trigger rapid restarts. Set PodDisruptionBudget with minAvailable to maintain service capacity during crash-restart cycles. This limits sustained DoS impact from repeated exploitation but does NOT prevent individual crashes.
  5. Monitor for crash-loop signatures — Alert on kube_pod_container_status_restarts_total spikes and grep container logs for runtime error: index out of range [0] with length 0 in routing.go. This provides post-exploitation detection and helps distinguish CVE-2026-84445 crashes from other Go panics.
What doesn't work
  • Rate limiting on the gRPC port — a single request triggers the crash, so rate limits at any practical threshold cannot prevent the initial kill. They only slow repeated exploitation after the first crash.
  • Application-layer WAF rules — gRPC uses HTTP/2 binary framing with protobuf payloads. Most WAFs inspect HTTP/1.1 text or JSON bodies and cannot reliably parse HTTP/2 pseudo-headers at the frame level to detect missing :authority.
  • Go recover() wrappers in application handlers — the panic occurs in the xDS routing interceptor *before* the application handler is invoked, so application-level recovery middleware never sees it.
  • Upgrading to grpc-go 1.83.0 or 1.83.1 — these versions are still in the vulnerable range. You need 1.83.2 or higher.
06 · Verification

Crowdsourced verification payload.

Run this script on any machine with access to the Go project source tree (developer workstation, CI runner, or build server). It requires no special privileges — only read access to go.mod and *.go source files. Invoke as: bash check_cve_2026_84445.sh /path/to/your/go/project

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2026-84445 Verification Script
# Checks if a Go project uses a vulnerable version of google.golang.org/grpc
# AND whether xds.NewGRPCServer() is in use (the only affected code path).
#
# Usage:  bash check_cve_2026_84445.sh /path/to/go/project
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit:   1 = vulnerable, 0 = patched, 2 = unknown

set -euo pipefail

PROJECT_DIR="${1:-.}"
GOMOD="$PROJECT_DIR/go.mod"

if [[ ! -f "$GOMOD" ]]; then
  echo "UNKNOWN - No go.mod found at $GOMOD"
  exit 2
fi

# Extract grpc-go version from go.mod (direct or indirect)
GRPC_LINE=$(grep -E 'google\.golang\.org/grpc\s+v' "$GOMOD" | head -1 || true)
if [[ -z "$GRPC_LINE" ]]; then
  echo "UNKNOWN - google.golang.org/grpc not found in go.mod"
  exit 2
fi

GRPC_VERSION=$(echo "$GRPC_LINE" | awk '{print $2}' | sed 's/^v//')
echo "[*] Found google.golang.org/grpc version: v$GRPC_VERSION"

# Check for xds.NewGRPCServer usage in Go source files
XDS_USED="no"
if grep -rq 'xds\.NewGRPCServer\|"google\.golang\.org/grpc/xds"' "$PROJECT_DIR" --include='*.go' 2>/dev/null; then
  XDS_USED="yes"
  echo "[!] xds.NewGRPCServer() or xds import detected in source code"
else
  echo "[i] No xds.NewGRPCServer() usage found (standard grpc.NewServer is NOT affected)"
fi

# Portable version comparison: returns 0 if $1 >= $2
version_gte() {
  printf '%s\n%s\n' "$2" "$1" | sort -V -C
}

# Determine vulnerability status
# Vulnerable ranges: < 1.82.2  OR  (>= 1.83.0 AND < 1.83.2)
VULN="no"
if version_gte "$GRPC_VERSION" "1.83.0" && ! version_gte "$GRPC_VERSION" "1.83.2"; then
  VULN="yes"
  RANGE="[1.83.0, 1.83.2)"
elif ! version_gte "$GRPC_VERSION" "1.82.2"; then
  VULN="yes"
  RANGE="(< 1.82.2)"
fi

if [[ "$VULN" == "yes" ]]; then
  if [[ "$XDS_USED" == "yes" ]]; then
    echo "VULNERABLE - grpc-go v$GRPC_VERSION in range $RANGE with xds.NewGRPCServer() usage"
    echo "  -> Upgrade to v1.82.2+ or v1.83.2+ immediately."
    exit 1
  else
    echo "VULNERABLE - grpc-go v$GRPC_VERSION in range $RANGE (dependency is vulnerable)"
    echo "  -> xds.NewGRPCServer() not detected in source; effective risk is LOW unless xDS is used at runtime."
    echo "  -> Upgrade to v1.82.2+ or v1.83.2+ as part of routine maintenance."
    exit 1
  fi
else
  echo "PATCHED - grpc-go v$GRPC_VERSION is not in the vulnerable range"
  exit 0
fi
07 · Sources

Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.