A bouncer checking IDs with the wrong font case lets everyone through the VIP rope
CVE-2026-84303 is an authorization-bypass flaw in gRPC-Go's xDS RBAC HTTP filter (internal/xds/httpfilter/rbac/rbac.go). The normalizeHeaderMatcher function does not lowercase header names before evaluation, but HTTP/2 metadata keys arrive lowercase per spec. Any DENY policy referencing a mixed-case header — e.g., X-Role, User-Agent, Content-Type — silently fails to match, causing the policy to fail open. A secondary issue allows reserved grpc- prefixed headers (blocked by gRFC A41) to be injected via casing tricks like Grpc-Status. All versions of google.golang.org/grpc prior to v1.83.1 are affected.
The GitLab Advisory Database tags this MEDIUM at CVSS 6.5. That score is defensible for the *narrow population* that actually runs xDS RBAC, but the advisory doesn't call out how niche the feature is. The vast majority of gRPC-Go deployments use standard interceptors or gateway-level auth — they never load the xDS RBAC HTTP filter at all. For those shops, this CVE is a no-op. For the subset running proxyless gRPC mesh with Istio or Traffic Director and relying on xDS-pushed RBAC policies, the impact is real: authorization rules silently stop working. We assess at 5.5 MEDIUM — meaningful where it hits, but the hit surface is small.
4 steps from start to impact.
Target runs gRPC-Go with xDS RBAC
xds.NewGRPCServer() and receive RBAC HTTP filter configuration from an xDS control plane (e.g., Istio istiod, Google Traffic Director). Without xDS RBAC, the vulnerable code path is never executed.- Target application imports google.golang.org/grpc/xds and uses xds.NewGRPCServer()
- xDS control plane pushes RBAC HTTP filter config to the server
- Most gRPC-Go services use standard grpc.NewServer() with interceptor-based auth — xDS RBAC is a niche proxyless-mesh feature
- GRPC_XDS_EXPERIMENTAL_RBAC env var must not be set to false
DENY policy references mixed-case headers
X-Role instead of x-role). Since HTTP/2 mandates lowercase headers and the filter does not normalize, the matcher will never match incoming metadata.- At least one DENY rule references a header name containing uppercase characters
- The policy was authored with conventional mixed-case HTTP header names
- Some policy generators (e.g., Istio AuthorizationPolicy) may already lowercase header names before pushing xDS config
- Operators who test their DENY rules would notice the silent failure
grpcurl admin endpoint or Istio istioctl proxy-config for mixed-case header matchersAttacker sends normal gRPC request
- Network access to the gRPC service endpoint
- Service may sit behind a mesh sidecar, L7 gateway, or network policy that independently enforces authorization
- mTLS or other transport-level controls may restrict who can connect
Authorization bypass achieved
grpc- prefixed metadata (e.g., Grpc-Status) which could confuse downstream processing.- Successful bypass of step 3
- Application-layer authorization checks (business logic, JWT validation in interceptors) still apply independently of xDS RBAC
- Impact is bounded to the single service, not lateral movement
The supporting signals.
| In-the-Wild Exploitation | No evidence. Not listed in CISA KEV. No GreyNoise or Shadowserver observations. No threat-actor campaigns reported as of 2026-09-20. |
|---|---|
| Proof-of-Concept | None public. No PoC repos found on GitHub or ExploitDB. Exploitation is trivial in concept (send a normal request) but requires a specific server-side misconfiguration to be impactful. |
| EPSS Score | 0.00311 (~bottom 30th percentile). FIRST model rates exploitation probability in next 30 days as negligible. |
| KEV Status | Not listed. No CISA KEV entry as of 2026-09-20. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N — Network-accessible, no privileges or interaction needed, but impact limited to low confidentiality and integrity. No availability impact. |
| Affected Versions | All versions of google.golang.org/grpc < v1.83.1. The vulnerable function is in internal/xds/httpfilter/rbac/rbac.go. |
| Fixed Version | v1.83.1 (released ~Aug 19, 2026). Also addressed in v1.83.2 alongside sibling advisories GHSA-2v4p-qf9q-27wj and GHSA-vp52-pcj8-j9qc. |
| Exposure Surface | gRPC-Go is an extremely popular Go module, but the xDS RBAC HTTP filter is only loaded by services using xds.NewGRPCServer() in proxyless mesh configurations (Istio, Traffic Director, custom xDS control planes). Estimated <5% of gRPC-Go installations use this feature. |
| Disclosure Date | 2026-09-01 (CVE published). GitHub advisory GHSA-qc2q-p7wx-3px3 published 2026-08-19. |
| Reporter | Not publicly attributed. Filed via gRPC-Go GitHub security advisory process. |
Why this verdict
- Narrow feature surface: The vulnerability only affects gRPC-Go servers using the xDS RBAC HTTP filter via
xds.NewGRPCServer(). This is a proxyless-mesh feature used by a small fraction (<5%) of the gRPC-Go installed base. Standardgrpc.NewServer()deployments are completely unaffected. - Policy-configuration-dependent: Even within xDS RBAC users, exploitation requires DENY rules that reference mixed-case header names. If the control plane (e.g., Istio) lowercases header names before pushing config, the vulnerability is not reachable.
- No attacker sophistication required, but no RCE either: The attacker simply sends a normal gRPC request — no payload crafting needed. However, the impact ceiling is authorization bypass on a single service, not code execution, lateral movement, or privilege escalation.
- No active exploitation or PoC: EPSS 0.00311, not KEV-listed, no public PoC, no observed campaigns. The threat is entirely theoretical as of September 2026.
- Role multiplier: gRPC-Go with xDS RBAC is deployed in (a) *Kubernetes microservices* using proxyless mesh — typical role, blast radius is service-level auth bypass; (b) *API gateways or ingress services* — higher-value but these typically have redundant auth layers (JWT, mTLS, gateway WAF); (c) *orchestration control planes* — rare, and control plane services typically use interceptor-based auth, not xDS RBAC. No high-value role produces domain takeover, fleet compromise, or supply-chain pivot from this bug alone. The floor does not trigger.
Why not higher?
Promoting to HIGH would require either active exploitation, a broader blast radius, or a path to code execution. This CVE delivers authorization bypass on a single service within a niche deployment pattern (proxyless xDS mesh). The attacker gains access to one service's protected RPCs — not domain admin, not fleet-wide impact, not persistent access. Redundant auth layers (mTLS, JWT interceptors, gateway policies) independently block the same traffic in most real architectures.
Why not lower?
Dropping to LOW would undervalue the silent-fail-open nature of this bug. When it does hit, DENY rules stop working with zero indication — no error, no log, no alert. An operator who wrote an RBAC policy and tested it with a sidecar proxy might never discover the proxyless path ignores it. The CVSS vector's AV:N/PR:N/UI:N combination means any network-reachable attacker benefits, and the CWE-863 classification (Incorrect Authorization) is architecturally serious even if scoped.
What to do — in priority order.
- Upgrade google.golang.org/grpc to v1.83.1 or later — The definitive fix. Update your go.mod dependency and rebuild. Per the noisgate MEDIUM remediation SLA, deploy within 365 days — but if you actively use xDS RBAC with mixed-case header DENY rules, treat this as urgent and patch within days.
- Audit xDS RBAC policies for mixed-case header matchers — Run
istioctl proxy-config listener <pod> -o jsonor dump the xDS config from your control plane. Search for headerMatcher entries with uppercase characters. Rewrite them to all-lowercase as a stopgap. No mitigation SLA applies for MEDIUM, but this is a 15-minute config fix. - Layer interceptor-based authorization independently of xDS RBAC — Add a gRPC unary/stream interceptor that performs authorization checks (JWT validation, service-account verification) so that xDS RBAC is not your sole enforcement point. Defense-in-depth ensures this class of filter bypass cannot silently degrade your security posture.
- Enable gRPC audit logging for RBAC decisions — If your xDS control plane supports it, enable RBAC audit logging to detect when DENY rules are not matching expected traffic. This provides detection coverage while you plan the upgrade.
- WAF rules — Web Application Firewalls operate at HTTP/1.1 or HTTP/2 frame level and do not inspect gRPC xDS RBAC policy evaluation logic. A WAF cannot compensate for a server-side policy-matching bug.
- Network segmentation alone — While limiting who can reach the gRPC port reduces exposure, it does not fix the silent DENY-rule failure. Authorized internal callers who should be denied specific RPCs will still bypass the policy.
- Upgrading Istio without upgrading grpc-go — If you run proxyless gRPC (no sidecar), the RBAC evaluation happens inside the Go binary. Upgrading your Istio control plane does not fix the client-side library bug.
Crowdsourced verification payload.
Run on any host or CI runner that has the Go project source tree. Requires read access to go.mod and go.sum. No root privileges needed. Example: bash check_cve_2026_84303.sh /path/to/your/go/project
#!/usr/bin/env bash\n# CVE-2026-84303 Checker - gRPC-Go xDS RBAC Header Case Bypass\n# Outputs: VULNERABLE / PATCHED / UNKNOWN\nset -euo pipefail\n\nTARGET_DIR=\"${1:-.}\"\nFIXED=\"1.83.1\"\n\nif [ ! -f \"$TARGET_DIR/go.mod\" ]; then\n echo \"UNKNOWN - no go.mod found in $TARGET_DIR\"\n exit 2\nfi\n\n# Check go.sum for the resolved version (handles replace directives)\nif [ -f \"$TARGET_DIR/go.sum\" ]; then\n VER=$(grep -oP 'google\\.golang\\.org/grpc v\\K[0-9]+\\.[0-9]+\\.[0-9]+' \"$TARGET_DIR/go.sum\" | sort -V | tail -1)\nfi\n\n# Fallback to go.mod\nif [ -z \"${VER:-}\" ]; then\n VER=$(grep -oP 'google\\.golang\\.org/grpc v\\K[0-9]+\\.[0-9]+\\.[0-9]+' \"$TARGET_DIR/go.mod\" | head -1)\nfi\n\nif [ -z \"${VER:-}\" ]; then\n echo \"UNKNOWN - google.golang.org/grpc not found in go.mod or go.sum\"\n exit 2\nfi\n\n# Also check if xDS RBAC is actually imported\nXDS_USED=\"no\"\nif grep -rq 'google.golang.org/grpc/xds' \"$TARGET_DIR/\" --include='*.go' 2>/dev/null; then\n XDS_USED=\"yes\"\nfi\n\n# Version comparison\nif printf '%s\\n%s' \"$FIXED\" \"$VER\" | sort -V -C; then\n echo \"PATCHED - grpc-go v$VER >= v$FIXED (xDS import detected: $XDS_USED)\"\n exit 0\nelse\n if [ \"$XDS_USED\" = \"yes\" ]; then\n echo \"VULNERABLE - grpc-go v$VER < v$FIXED AND xDS package imported\"\n exit 1\n else\n echo \"VULNERABLE - grpc-go v$VER < v$FIXED (xDS not imported - likely not exploitable)\"\n exit 1\n fi\nfiWhat defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.