CVE-2026-126367: @grpc/grpc-js: safe_regex incorrectly applies partial string matching for patterns with alternation

Published Nov 12, 2026
·
Updated

@grpc/grpc-js implements the core functionality of gRPC purely in JavaScript, without a C++ addon. Before 1.13.2, and from 1.14.0 through 1.14.1, the @grpc/grpc-js-xds SafeRegexValueMatcher and PathSafeRegexValueMatcher add start and end anchors without grouping a supplied top-level alternation. An expression intended to match one of several complete values can therefore match a prefix, substring, or suffix. The affected matchers are used for route selection, xDS credential identity matching, and RBAC URL path, principal name, server name, and header rules. An ALLOW policy using an alternation can consequently accept a method, certificate identity, or header value outside the intended set, while a DENY policy becomes broader rather than permissive. This issue is fixed in versions 1.13.2 and 1.14.2.

Other sources

Summary

The StringMatcher/PathMatcher for saferegex builds its RE2 as ^${regex}$ with no surrounding group. Because alternation has the lowest precedence, a pattern "a|b|c" compiles to /^a|b|c$/ -- "starts with a" OR "contains b" OR "ends with c" instead of a full match of the whole value. Configurations with saferegex matchers that use a regex alternation (a natural way to list methods or service identities) therefore apply partial string matches. This impacts route selection, xDS credentials, and RBAC.

Details

src/matcher.ts: SafeRegexValueMatcher and PathSafeRegexValueMatcher both do ts this.targetRegexImpl = new RE2(^${targetRegex}$, 'u');

and apply() returns targetRegexImpl.test(value). With a top-level alternation the anchors bind only to the first/last branch.

https://github.com/grpc/grpc-node/blob/e742b11bd8039f3dbea4cd29afdf5d95a8ba6b92/packages/grpc-js-xds/src/matcher.ts#L59

https://github.com/grpc/grpc-node/blob/e742b11bd8039f3dbea4cd29afdf5d95a8ba6b92/packages/grpc-js-xds/src/matcher.ts#L232

src/route.ts (getPredicateForStringMatcher / getPredicateForHeaderMatcher) builds these for every saferegex StringMatcher/HeaderMatcher, and src/rbac.ts uses them for RBAC urlpath permissions/principals, authenticated.principalname (mTLS SAN/CN), requestedservername and header rules. So an ALLOW rule written with an alternation grants access to method names, certificate identities or header values that extend an intended one. DENY policies only become broader (fail-safe).

https://github.com/grpc/grpc-node/blob/e742b11bd8039f3dbea4cd29afdf5d95a8ba6b92/packages/grpc-js-xds/src/route.ts#L28

https://github.com/grpc/grpc-node/blob/e742b11bd8039f3dbea4cd29afdf5d95a8ba6b92/packages/grpc-js-xds/src/route.ts#L47

Proof of concept

In a scratch directory:

npm init -y npm i @grpc/grpc-js-xds@1.14.1 @grpc/grpc-js node poc.cjs

poc.cjs calls the exported RBAC engine directly (the functions grpc-js uses to make the authorization decision); no server or network:

js const { parseConfig } = require('@grpc/grpc-js-xds/build/src/rbac.js') const { SafeRegexValueMatcher } = require('@grpc/grpc-js-xds/build/src/matcher.js') const { Metadata } = require('@grpc/grpc-js')

console.log(new SafeRegexValueMatcher('admin|editor').toString()) // SafeRegex(/^admin|editor$/u)

const sr = regex => ({ matchpattern: 'saferegex', saferegex: { regex } }) const info = urlPath => ({ urlPath, headers: new Metadata(), tls: true, peerCertificate: null, destinationIp: '10.0.0.1', destinationPort: 443, sourceIp: '10.0.0.2' }) const g = parseConfig({ action: 'ALLOW', policies: { p: { permissions: [{ rule: 'urlpath', urlpath: { path: sr('/acme.Users/GetUser|/acme.Users/ListUsers') } }], principals: [{ identifier: 'any', any: true }] } } })

console.log('GetUser ', g.apply(info('/acme.Users/GetUser'))) // true (intended) console.log('DeleteUser ', g.apply(info('/acme.Users/DeleteUser'))) // false (control) console.log('GetUserSecrets', g.apply(info('/acme.Users/GetUserSecrets'))) // true <-- BYPASS

Observed (grpc-js-xds 1.14.1, grpc-js 1.14.6):

matcher "admin|editor" -> SafeRegex(/^admin|editor$/u); apply("administrator")=true, apply("not-an-editor")=true ALLOW urlpath /acme.Users/GetUser|/acme.Users/ListUsers: /acme.Users/GetUser -> ALLOWED (intended) /acme.Users/DeleteUser -> denied (control) /acme.Users/GetUserSecrets -> ALLOWED <-- bypass (policy intends deny) control, same regex as (?:...|...): /acme.Users/GetUserSecrets -> denied ALLOW authenticated principalname spiffe://prod/ns/web/sa/frontend|...ops/sa/admin: spiffe://prod/ns/web/sa/frontend-batch -> ALLOWED <-- bypass

Impact

Users of @grpc/grpc-js-xds who are using saferegex matchers with alternation for route selection, xDS credentials SAN matchers, or RBAC rules may see incorrectly permissive behavior.

— GitHub

Affected Software

2 affected componentsFixes available
npm/@grpc/grpc-js-xds<1.13.2
1.13.2
npm/@grpc/grpc-js-xds>=1.14.0<1.14.2
1.14.2

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/@grpc/grpc-js-xds to a version that resolves this vulnerability.

    Fixed in 1.13.2
  2. Upgrade

    Upgrade npm/@grpc/grpc-js-xds to a version that resolves this vulnerability.

    Fixed in 1.14.2
  3. Upgrade

    Upgrade @grpc/grpc-js-xds to a version that resolves this vulnerability.

    Fixed in 1.13.2
  4. Upgrade

    Upgrade @grpc/grpc-js-xds to a version that resolves this vulnerability.

    Fixed in 1.14.2

Event History

Nov 12, 2026
CVE Published
via MITRE·10:43 PM
Data Sourced
via MITRE·10:43 PM
DescriptionSeverityWeakness
Advisory Published
via GitHub·11:21 PM
Data Sourced
via GitHub·11:21 PM
DescriptionSeverityWeaknessAffected Software
Nov 13, 2026
Data Sourced
via NVD·12:20 AM
DescriptionSeverityWeakness

Frequently Asked Questions

1

Which deployments are exposed to unintended access decisions?

Deployments using @grpc/grpc-js-xds safe_regex matchers with top-level alternation are affected. Relevant uses include route selection, xDS credential identity matching, and RBAC rules for URL paths, principal names, server names, and headers.

2

What must an attacker provide to exploit an ALLOW policy?

The attacker must supply a value that satisfies one incorrectly unanchored alternation branch, such as a value with the permitted prefix, a matching substring, or the permitted suffix. This can cause an ALLOW policy intended to permit only complete values to accept values outside the intended set.

3

How do DENY policies behave when affected?

An affected DENY policy becomes broader rather than permissive. Values that only partially match an alternation branch can be denied unexpectedly.

4

Which versions are affected and which contain the fix?

Affected versions are those before 1.13.2 and versions 1.14.0 through 1.14.1. The issue is fixed in 1.13.2 and 1.14.2.

5

How can I identify vulnerable matcher configurations?

Review SafeRegexValueMatcher and PathSafeRegexValueMatcher configurations for safe_regex expressions containing top-level alternation, such as a|b|c. These patterns were interpreted as ^a|b|c$ rather than as a full-string match of the complete alternation.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203