@grpc/grpc-js: safe_regex incorrectly applies partial string matching for patterns with alternation
cve-program · CVE-2026-126367
Published@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.
Read the publisher's advisoryeuvd · EUVD-2026-124775
Published@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.
Read the publisher's advisorynvd · CVE-2026-126367
Published@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.
Read the publisher's advisoryosv · GHSA-r7hq-q2xm-6c5m
Published### Summary The StringMatcher/PathMatcher for `safe_regex` 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 `safe_regex` 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 `safe_regex` `StringMatcher`/`HeaderMatcher`, and src/rbac.ts uses them for RBAC `url_path` `permissions`/`principals`, `authenticated.principal_name` (mTLS SAN/CN), `requested_server_name` 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/[email protected] @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 => ({ match_pattern: 'safe_regex', safe_regex: { 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: 'url_path', url_path: { 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 url_path /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 principal_name 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 `safe_regex` matchers with alternation for route selection, xDS credentials SAN matchers, or RBAC rules may see incorrectly permissive behavior.
Read the publisher's advisoryAffected versions, risk and source history
Related advisories and sources
Publishers link these advisories through the identifiers shown below. A shared identifier or date alone does not tell you whether your software is affected or whether the advisories describe the same cause.
CVE-2026-126367 · CVE overview and exploitation status
cve-program · CVE-2026-126367
- https://github.com/grpc/grpc-node/security/advisories/GHSA-r7hq-q2xm-6c5m
- https://github.com/grpc/grpc-node/commit/3fc3b0ebf7a89d64843a73679951142d33b40cb1
- https://github.com/grpc/grpc-node/commit/57a67e96babcb29b6eabc1833221ccf2fa152d43
- https://github.com/grpc/grpc-node/releases/tag/@grpc/[email protected]
- https://github.com/grpc/grpc-node/releases/tag/@grpc/[email protected]
euvd · EUVD-2026-124775
- https://github.com/grpc/grpc-node/security/advisories/GHSA-r7hq-q2xm-6c5m
- https://github.com/grpc/grpc-node/commit/3fc3b0ebf7a89d64843a73679951142d33b40cb1
- https://github.com/grpc/grpc-node/commit/57a67e96babcb29b6eabc1833221ccf2fa152d43
- https://github.com/grpc/grpc-node/releases/tag/@grpc/[email protected]
- https://github.com/grpc/grpc-node/releases/tag/@grpc/[email protected]
nvd · CVE-2026-126367
- https://github.com/grpc/grpc-node/commit/3fc3b0ebf7a89d64843a73679951142d33b40cb1
- https://github.com/grpc/grpc-node/commit/57a67e96babcb29b6eabc1833221ccf2fa152d43
- https://github.com/grpc/grpc-node/releases/tag/@grpc/[email protected]
- https://github.com/grpc/grpc-node/releases/tag/@grpc/[email protected]
- https://github.com/grpc/grpc-node/security/advisories/GHSA-r7hq-q2xm-6c5m
osv · GHSA-r7hq-q2xm-6c5m
- https://github.com/grpc/grpc-node/security/advisories/GHSA-r7hq-q2xm-6c5m
- https://github.com/grpc/grpc-node/commit/3fc3b0ebf7a89d64843a73679951142d33b40cb1
- https://github.com/grpc/grpc-node/commit/57a67e96babcb29b6eabc1833221ccf2fa152d43
- https://github.com/grpc/grpc-node
- https://github.com/grpc/grpc-node/releases/tag/@grpc/[email protected]
- https://github.com/grpc/grpc-node/releases/tag/@grpc/[email protected]
Related changes
Linked by CVE identifier- @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 an… · Advisory content revised · 15 Nov 2026
- @grpc/grpc-js: safe_regex incorrectly applies partial string matching for patterns with alternation · Newly collected advisory · 13 Nov 2026
- @grpc/grpc-js: safe_regex incorrectly applies partial string matching for patterns with alternation · Newly collected advisory · 13 Nov 2026