← Back to Feed CACHED · 2026-10-08 11:17:41 · CACHE_KEY CVE-2026-33186
CVE-2026-33186 · CWE-285 · Disclosed 2026-03-20

gRPC-Go Authorization Bypass via Missing Leading Slash in HTTP/2 :path

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

The front door checks your badge but not if you wrote your name in crayon

gRPC-Go versions before 1.79.3 accepted HTTP/2 requests where the :path pseudo-header omitted the mandatory leading slash — Service/Method instead of /Service/Method. The server's routing layer found the right handler regardless, but the authorization engine (google.golang.org/grpc/authz or any custom interceptor reading info.FullMethod) evaluated the raw, un-normalized path string. Deny rules written against canonical paths (starting with /) never matched the slash-less variant. If the policy had a fallback allow rule — the common "deny these sensitive methods, allow everything else" pattern — the request sailed through. Affected: all google.golang.org/grpc versions prior to v1.79.3. Fixed in v1.79.3 (PR #8981).

The vendor-assigned CVSS 9.1 CRITICAL is technically defensible for the worst case: an internet-facing gRPC server using the official authz interceptor with deny+allow policies. In practice, it overstates the risk for most enterprise deployments. The vast majority of gRPC-Go services sit behind L7 proxies (Envoy, NGINX, AWS ALB, GCP CLB) that enforce RFC 9113 path compliance and would reject or normalize the malformed :path before it reaches the Go process. The vulnerability also requires a specific authorization configuration — path-based interceptors with deny rules *and* a fallback allow — that represents a subset of all gRPC-Go deployments. Many teams rely on service mesh authorization, mTLS, or external API gateways rather than gRPC-Go's built-in RBAC. These friction points compound to bring real-world severity from CRITICAL down to HIGH.

"Drop a slash, skip the bouncer — but most gRPC services sit behind proxies that block it."
02 · The Attack Path

5 steps from start to impact.

STEP 01

Identify a gRPC-Go endpoint

The attacker locates a gRPC service endpoint through service enumeration, DNS records, or probing common gRPC ports (443 with h2, or 50051). Tools like grpcurl or Shodan dorks for gRPC reflection endpoints surface candidates. The attacker needs to reach the gRPC server's TCP port with HTTP/2.
Conditions required:
  • Network reachability to the gRPC endpoint (direct internet exposure or internal network position)
Where this breaks in practice:
  • Most gRPC services are internal microservices not exposed to the internet
  • Typically sit behind L7 load balancers, API gateways, or service mesh sidecars
Detection/coverage: Network perimeter monitoring; gRPC reflection disabled in production reduces enumeration surface
STEP 02

Confirm path-based authorization is active

The attacker sends a legitimate request to a known-protected method (e.g., /AdminService/DeleteUser) and observes a PERMISSION_DENIED or UNAUTHENTICATED response. This confirms path-based RBAC is enforced. Without this confirmation, the bypass has no effect — a server with no authz interceptor simply handles every request.
Conditions required:
  • Server must use google.golang.org/grpc/authz or a custom interceptor reading info.FullMethod
  • Authorization policy must use deny rules with a fallback allow
Where this breaks in practice:
  • Many deployments use external authorization (service mesh, API gateway, mTLS identity) rather than gRPC-Go's built-in authz
  • The official grpc/authz package sees moderate but not universal adoption
Detection/coverage: Standard gRPC server access logs capture this probe as a normal denied request
STEP 03

Craft a slash-less :path HTTP/2 frame

Using Python's h2 library, curl --http2, or any raw HTTP/2 frame writer, the attacker constructs a HEADERS frame where :path omits the leading slash: AdminService/DeleteUser instead of /AdminService/DeleteUser. The public PoC by JohannesLks is a ~50-line Python script. No credentials, cookies, or tokens are needed.
Conditions required:
  • Ability to send raw HTTP/2 frames (not just standard gRPC client calls, which always include the leading slash)
Where this breaks in practice:
  • Essentially none — tooling is freely available and trivial to use
Detection/coverage: WAF/IDS rules inspecting HTTP/2 :path for RFC 9113 compliance (missing leading slash); gRPC-Go verbose logging may capture non-canonical path
STEP 04

Bypass deny rules via path mismatch

The gRPC-Go transport layer accepts the non-canonical path and routes the request to the correct handler. The authz interceptor evaluates the raw path AdminService/DeleteUser against its policy. The deny rule targeting /AdminService/DeleteUser does not match because the leading / is missing. The policy falls through to the default allow rule, and the request is authorized.
Conditions required:
  • Policy must have explicit deny rules (with canonical paths) AND a fallback allow rule
  • A deny-all-by-default policy is NOT bypassed
Where this breaks in practice:
  • The deny+allow pattern is common but not universal
  • Strict deny-by-default policies are immune
Detection/coverage: Authorization audit logs showing access to a normally-denied method; anomaly detection on method-call patterns
STEP 05

Execute unauthorized operations

With authorization bypassed, the attacker invokes any gRPC method that was protected only by path-based deny rules. Impact depends on what those methods do: administrative operations, data exfiltration, state mutation, privilege escalation within the application. The attacker has the same capability as a legitimately authorized caller.
Conditions required:
  • Protected methods must not have secondary authorization checks (per-field validation, row-level security, handler-level auth)
Where this breaks in practice:
  • Well-designed services may have defense-in-depth with handler-level auth checks
Detection/coverage: Application-level audit trails; behavioral analytics on method invocation patterns
03 · Compensating Control

1
HIGH 7.5→IGNORE 0.0
SEVERITY REDUCED
Upgrade gRPC-Go to v1.79.3+ — The definitive fix. Run go get google.golang.org/[email protected] && go mod tidy in every affected module, rebuild, and redeploy. The patch rejects slash-less :path values at the transport layer before any interceptor runs. One-line dependency bump with no breaking API changes. Per noisgate mitigation SLA for HIGH, deploy within 30 days.
2
HIGH 7.5→LOW 2.0
SEVERITY REDUCED
Deploy a validating unary+stream interceptor — If patching requires a longer release cycle, add a custom interceptor at the front of the chain that checks info.FullMethod starts with / and returns codes.InvalidArgument if not. This is the vendor-recommended interim mitigation. Deploy within 30 days per the noisgate mitigation SLA for HIGH.
3
HIGH 7.5→LOW 2.5
SEVERITY REDUCED
Enforce RFC 9113 path compliance at L7 proxy — Configure Envoy, NGINX, or cloud ALB to reject or normalize HTTP/2 requests where :path does not start with /. Envoy's normalize_path and NGINX's grpc_pass with strict path checking accomplish this. Effective only when ALL paths to the gRPC server transit the proxy. Deploy within 30 days per the noisgate mitigation SLA for HIGH.
4
HIGH 7.5→LOW 2.0
SEVERITY REDUCED
Switch to deny-by-default authorization policies — Rewrite RBAC policies to use explicit allow rules for each permitted method with no fallback allow. This eliminates the policy pattern the bypass exploits. Even without patching, a deny-by-default policy cannot be bypassed because there is no fallback allow to fall through to. Deploy within 30 days per the noisgate mitigation SLA for HIGH.
What doesn't work
  • Network-level firewalling (L3/L4): Blocking ports or IPs does not help if the attacker has legitimate network access. The exploit travels over a normal HTTP/2 connection on the standard port.
  • mTLS between services: mTLS authenticates caller identity but does not validate :path header content. A compromised service with a valid mTLS certificate can still send slash-less paths.
  • Rate limiting: The exploit requires a single request. Rate limiting has no meaningful effect on a one-shot authorization bypass.
  • Standard gRPC client library hardening: All well-behaved gRPC clients automatically include the leading slash. The exploit requires a raw HTTP/2 frame writer, so hardening standard clients does nothing against an attacker who bypasses them.
04 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNo evidence. Not listed in CISA KEV. No campaigns attributed. No GreyNoise or Shadowserver tags observed as of 2026-10-08.
Proof of conceptPublic PoC available. JohannesLks/CVE-2026-33186 — Python script using h2 library, ~50 lines, sends baseline/attack/control requests. Published shortly after disclosure. 1 star, 0 forks. No Metasploit module or Nuclei template identified.
EPSS1.625% (75th percentile). Low probability of exploitation in next 30 days relative to all CVEs, but notably above median.
CISA KEVNot listed as of 2026-10-08.
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N (9.1). Network-attackable, low complexity, no privileges, no interaction. High C+I, no availability impact.
Affected versionsgoogle.golang.org/grpc < v1.79.3. All prior versions using grpc/authz or custom FullMethod-based interceptors with deny+allow policies.
Fixed versionv1.79.3. Fix rejects any :path without a leading slash at the transport layer with codes.Unimplemented. Patch: PR #8981.
Downstream impactConfirmed affected dependencies: Traefik (GHSA-46wh-3698-f2cx), Kubernetes cluster-autoscaler v1.35.0, Envoy Gateway v1.6.6, DataDog Agent (#48151), Istio Service Bridge.
Disclosure timelineGitHub Advisory (GHSA-p77j-4mvh-x3m3): 2026-03-17. NVD: 2026-03-20. Go Vuln DB: GO-2026-4762.
ReporterMariuszMaik (@MariuszMaik on GitHub).

Sources.

  1. GitHub Advisory GHSA-p77j-4mvh-x3m3
  2. NVD — CVE-2026-33186
  3. Go Vulnerability Database — GO-2026-4762
  4. JohannesLks/CVE-2026-33186 PoC
  5. Traefik Advisory — GHSA-46wh-3698-f2cx
  6. ByteIota — gRPC-Go CVE-2026-33186 Analysis
  7. Red Hat Customer Portal — CVE-2026-33186
  8. DataDog Agent Issue #48151
05 · The Call

Final Verdict
↓ DOWNGRADED to HIGH (7.5/10)

Why this verdict

  • Configuration prerequisite narrows the population. The bypass requires three conditions: vulnerable gRPC-Go version + path-based authz interceptor (grpc/authz or custom FullMethod-based) + deny rules with a fallback allow. A deny-by-default policy is immune. Estimated ~15–25% of gRPC-Go servers use built-in path-based RBAC with this policy shape.
  • L7 proxy layer provides natural mitigation. Envoy (Istio sidecars), NGINX 1.31.4+, AWS ALB, and GCP CLB enforce RFC 9113 compliance on HTTP/2 :path headers. Any gRPC service behind these proxies is protected without patching. In enterprise microservice architectures, direct client-to-server gRPC without an intermediary proxy is the exception.
  • Internal network positioning required for most targets. gRPC services are overwhelmingly internal microservices. Direct internet exposure of raw gRPC endpoints is rare in enterprise environments. Exploitation against internal services implies a prior compromise stage.
  • Role multiplier: gRPC-Go is a library, not a high-value component by definition. It runs *inside* high-value infrastructure (Kubernetes, Istio, Traefik, DataDog), but those projects implement their own authorization logic rather than relying on grpc/authz. Kubernetes uses its own RBAC and admission controllers. Istio enforces authorization at the sidecar level. Traefik has its own middleware chain. The downstream advisories are about the dependency being present, not the auth bypass being exercisable. For custom microservices that *do* use grpc/authz — financial APIs, healthcare backends, admin services — the blast radius is service-scoped (data exfiltration, unauthorized operations) but does not cascade to domain takeover, fleet compromise, or supply-chain pivot.
  • Role multiplier floor: HIGH. When a custom Go microservice deliberately uses grpc/authz to protect sensitive administrative or data-access methods (financial transactions, patient records, admin APIs), the bypass grants full unauthenticated access. This represents a plausible high-value-role outcome (mass data egress) for a non-trivial fraction of the installed base. The floor is HIGH.

Why not higher?

The three-condition prerequisite chain (vulnerable version + authz interceptor + deny+allow policy) compounds with L7 proxy mitigation and internal-network positioning to substantially narrow the reachable population. Confirmed high-value downstream projects (Kubernetes, Istio, Traefik) do not exercise the vulnerable code path for their own authorization. No in-the-wild exploitation after 6+ months. EPSS at the 75th percentile — elevated but not alarming.

Why not lower?

The vulnerability requires zero credentials and zero user interaction. When conditions align, every deny rule in the policy is defeated — complete authorization bypass. A public PoC exists and exploitation is trivial (~50 lines of Python). Custom microservices that chose grpc/authz for access control to sensitive methods face full bypass, and those deployments represent a non-negligible share of the gRPC-Go ecosystem. The floor holds at HIGH.

06 · Verification

Crowdsourced verification payload.

Run on any host where your Go modules are built or checked out. It inspects go.mod / go.sum to determine whether the installed google.golang.org/grpc version is vulnerable. No special privileges required. Usage: bash check_cve_2026_33186.sh /path/to/your/go/module

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# check_cve_2026_33186.sh — Detect CVE-2026-33186 (gRPC-Go auth bypass)
# Usage: bash check_cve_2026_33186.sh /path/to/go/module
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN

set -euo pipefail

MOD_DIR="${1:-.}"
GOMOD="${MOD_DIR}/go.mod"
FIXED_VERSION="1.79.3"

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

# Extract the google.golang.org/grpc version from go.mod
GRPC_LINE=$(grep -E '^\s+google\.golang\.org/grpc\s+v' "$GOMOD" | head -1 || true)

if [[ -z "$GRPC_LINE" ]]; then
  GRPC_LINE=$(grep -E '^module\s+google\.golang\.org/grpc' "$GOMOD" || true)
  if [[ -n "$GRPC_LINE" ]]; then
    echo "UNKNOWN — this IS the grpc-go module itself; check its version tag"
    exit 2
  fi
  if [[ -f "${MOD_DIR}/go.sum" ]]; then
    GRPC_LINE=$(grep -E 'google\.golang\.org/grpc\s+v' "${MOD_DIR}/go.sum" | tail -1 || true)
  fi
  if [[ -z "$GRPC_LINE" ]]; then
    echo "UNKNOWN — google.golang.org/grpc not found in go.mod or go.sum"
    exit 2
  fi
fi

VERSION=$(echo "$GRPC_LINE" | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1 | sed 's/^v//')

if [[ -z "$VERSION" ]]; then
  echo "UNKNOWN — could not parse grpc-go version from: $GRPC_LINE"
  exit 2
fi

MIN_SAFE=$(printf '%s\n%s' "$VERSION" "$FIXED_VERSION" | sort -V | head -1)

if [[ "$MIN_SAFE" == "$FIXED_VERSION" ]] || [[ "$VERSION" == "$FIXED_VERSION" ]]; then
  echo "PATCHED — google.golang.org/grpc v${VERSION} >= v${FIXED_VERSION}"
  exit 0
else
  echo "VULNERABLE — google.golang.org/grpc v${VERSION} < v${FIXED_VERSION} (CVE-2026-33186)"
  echo "  Fix: go get google.golang.org/grpc@v${FIXED_VERSION} && go mod tidy"
  exit 1
fi