CVE-2026-128065: Authorization Bypass via Unapplied RBAC Overrides in @grpc/grpc-js-xds

Vulnerability ID: CVE-2026-128065
CVSS Score: 6.9
Published: 2026-11-12

CVE-2026-128065 (also tracked as GHSA-gg5j-6742-v827) is an authorization bypass vulnerability affecting the @grpc/grpc-js-xds library in the Node.js gRPC ecosystem. In versions 1.14.0 and 1.14.1, XdsServer acknowledges Route and VirtualHost resources from an xDS control plane while failing to parse, store, or apply RBACPerRoute override configurations. When experimental RBAC is enabled and a broad top-level ALLOW policy is paired with restrictive VirtualHost or Route overrides, the server evaluates requests strictly against the top-level policy, permitting unauthorized RPC execution.

TL;DR

An incorrect authorization flaw (CWE-863) in @grpc/grpc-js-xds versions 1.14.0 and 1.14.1 causes XdsServer to ignore VirtualHost and Route-level RBAC override configurations. Deployments relying on permissive top-level RBAC filters combined with restrictive route-specific overrides will fail to block unauthorized RPC requests. Upgrading @grpc/grpc-js-xds to version 1.14.2 resolves the issue.

⚠️ Exploit Status: POC

Technical Details

  • CVE ID: CVE-2026-128065 (GHSA-gg5j-6742-v827)
  • Weakness Class: CWE-863 (Incorrect Authorization)
  • CVSS v4.0 Score: 6.9 Medium (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N)
  • Affected Component: @grpc/grpc-js-xds (>= 1.14.0, < 1.14.2)
  • Attack Vector: Network (Unauthenticated gRPC Request)
  • Security Impact: Bypass of VirtualHost and Route RBACPerRoute authorization policies
  • Exploit Status: PoC Available (Official Unit Tests)
  • Patched Version: @grpc/grpc-js-xds 1.14.2

Affected Systems

  • @grpc/grpc-js-xds
  • grpc-node XdsServer
  • @grpc/grpc-js-xds: >= 1.14.0, < 1.14.2 (Fixed in: 1.14.2)

Code Analysis

Commit: b8f3ced

grpc-js-xds: Fix RBAC override config handling

File: packages/grpc-js-xds/src/http-filter/rbac-filter.ts @@ -171,5 +171,10 @@ export function setup() { parseOverrideFilterConfig: parseOverrideRbacConfig, createServerFilter: createRbacServerFilter }); + registerHttpFilter(RBAC_FILTER_OVERRIDE_URL, { + parseTopLevelFilterConfig: parseTopLevelRbacConfig, + parseOverrideFilterConfig: parseOverrideRbacConfig, + createServerFilter: createRbacServerFilter + }); } } File: packages/grpc-js-xds/src/server.ts @@ -170,7 +170,7 @@ class FilterChainEntry { const filterConfig = parseTopLevelFilterConfig(filter.typed_config!, false); if (filterConfig) { const filterOverrideConfigMap = new Map<string, HttpFilterConfig>(); - this.overrideConfigMaps.set(filterConfig.typeUrl, filterOverrideConfigMap); + this.overrideConfigMaps.set(filter.name, filterOverrideConfigMap); const filterInterceptor = createServerHttpFilter(filterConfig, filterOverrideConfigMap); if (filterInterceptor) { httpFilterInterceptors.push(filterInterceptor); @@ -227,6 +227,14 @@ class FilterChainEntry { domains: virtualHost.domains, routes: [] }; + // filter name -> config + const virtualHostOverrideConfigs = new Map<string, HttpFilterConfig>() + for (const [filterName, overrideConfig] of Object.entries(virtualHost.typed_per_filter_config)) { + const parsedConfig = parseOverrideFilterConfig(overrideConfig); + if (parsedConfig) { + virtualHostOverrideConfigs.set(filterName, parsedConfig); + } + } for (const [routeIndex, route] of virtualHost.routes.entries()) { const routeEntry: RouteEntry = { id: `virtualhost=${virtualHostIndex} route=${routeIndex}`, @@ -238,10 +246,19 @@ class FilterChainEntry { this.logConfigurationError('For domains matching [' + virtualHostEntry.domains + '] requests will be rejected for routes matching ' + routeEntry.matcher.toString()); } virtualHostEntry.routes.push(routeEntry); - for (const [filterName, overrideConfig] of Object.entries(route.typed_per_filter_config)) { - const parsedConfig = parseOverrideFilterConfig(overrideConfig); - if (parsedConfig) { - this.overrideConfigMaps.get(filterName)?.set(routeEntry.id, parsedConfig); + for (const filterName of this.overrideConfigMaps.keys()) { + // Use the virtual host override by default + let routeOverrideConfig = virtualHostOverrideConfigs.get(filterName); + if (filterName in route.typed_per_filter_config) { + const parsedConfig = parseOverrideFilterConfig(route.typed_per_filter_config[filterName]); + if (parsedConfig) { + /* If the route has an override config and it parses successfully, + * use it instead because it is more specific. */ + routeOverrideConfig = parsedConfig; + } + } + if (routeOverrideConfig) { + this.overrideConfigMaps.get(filterName)!.set(routeEntry.id, routeOverrideConfig); } } } 

Exploit Details

  • GitHub: Official unit and integration regression tests demonstrating VirtualHost and Route-level RBAC override bypass scenarios.

Mitigation Strategies

  • Upgrade @grpc/grpc-js-xds to version 1.14.2 or later to ensure RBACPerRoute overrides in VirtualHost and Route resources are properly parsed and enforced.
  • Consolidate RBAC policies into the top-level HTTP filter configuration on the Listener resource rather than relying on VirtualHost or Route typed_per_filter_config overrides.
  • Implement application-layer authorization checks using native @grpc/grpc-js server interceptors to validate caller identity and permissions per RPC method.

Remediation Steps:

  1. Audit Node.js projects and container images to identify installations of @grpc/grpc-js-xds versions 1.14.0 and 1.14.1.
  2. Update package.json to require @grpc/grpc-js-xds version ^1.14.2 and run npm install or yarn upgrade.
  3. Verify that xDS RouteConfiguration resources containing RBACPerRoute entries return status.PERMISSION_DENIED (code 7) for unauthorized test RPCs.
  4. Redeploy affected Node.js gRPC server workloads.

References

Read the full report for CVE-2026-128065 on our website for more details including interactive diagrams and full exploit analysis.