XdsServer in @grpc/grpc-js-xds does not apply RBACPerRoute overrides from matching Route or VirtualHost resources. When a trusted xDS control plane supplies a broad top-level ALLOW policy and a stricter override, XdsServer ACKs the resources but evaluates the RPC under the top-level policy.
parseOverrideFilterConfig() in packages/grpc-js-xds/src/http-filter.ts:225-257 looks up FILTER_REGISTRY using the override message type:
type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBACPerRoute
Source: https://github.com/grpc/grpc-node/blob/56567d9604b4e45cdca0d2e3c2a60ac227ee659d/packages/grpc-js-xds/src/http-filter.ts#L225-L257
setup() in packages/grpc-js-xds/src/http-filter/rbac-filter.ts:167-173 registers the filter only under the top-level RBAC type:
type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC
Source: https://github.com/grpc/grpc-node/blob/56567d9604b4e45cdca0d2e3c2a60ac227ee659d/packages/grpc-js-xds/src/http-filter/rbac-filter.ts#L167-L173
The lookup returns null even though the registered entry contains parseOverrideRbacConfig(), and server.ts silently skips the override.
overrideConfigMaps in server.ts:99-102 is documented as keyed by HTTP filter name, but server.ts:169-174 stores each map under filterConfig.typeUrl.
Route overrides are later looked up by their typed_per_filter_config key, which is the HttpFilter.name. An ordinary key such as rbac therefore misses the stored map.
handleRouteConfigurationResource() in server.ts:225-249 reads route.typed_per_filter_config but never reads virtualHost.typed_per_filter_config.
When no override reaches the RBAC interceptor, rbac-filter.ts:125-155 evaluates the broader top-level policy.
Set:
GRPC_XDS_EXPERIMENTAL_RBAC=true
Run XdsServer with a protected unary handler.
Have the ADS control plane deliver a Listener containing an RBAC HTTP filter named rbac with a top-level ALLOW-any policy:
name: rbac
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC
rules:
action: ALLOW
policies:
allow-any:
principals: [{ any: true }]
permissions: [{ any: true }]
Deliver a matching non-forwarding route with this override:
typed_per_filter_config:
rbac:
"@type": type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBACPerRoute
rbac:
rules:
action: DENY
policies:
deny-any:
principals: [{ any: true }]
permissions: [{ any: true }]
Invoke the protected unary method without credentials.
Expected: The route-specific DENY policy rejects the RPC before the protected handler runs.
Observed: XdsServer ACKs the resources, retains the top-level ALLOW policy, and runs the protected handler.
Listener and RouteConfiguration: ACKED
gRPC status: OK
handler invocations: 1
response: PROTECTED_SECRET_RECORD_RBAC_OVERRIDE
Users of @grpc/grpc-js-xds who are using RBAC-based authentication with override configurations may unintentionally accept some requests that should be rejected.
{
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-11-12T22:55:47Z",
"nvd_published_at": null,
"severity": "MODERATE"
}