CVE-2020-16844
Description
In Istio 1.5.0 though 1.5.8 and Istio 1.6.0 through 1.6.7, when users specify an AuthorizationPolicy resource with DENY actions using wildcard suffixes (e.g. *-some-suffix) for source principals or namespace fields, callers will never be denied access, bypassing the intended policy.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
In Istio 1.5.0-1.5.8 and 1.6.0-1.6.7, AuthorizationPolicy DENY rules with wildcard suffixes fail to deny access, bypassing the intended policy.
Vulnerability
In Istio versions 1.5.0 through 1.5.8 and 1.6.0 through 1.6.7, the authorization policy enforcement contains a bug when processing DENY actions with wildcard suffixes in source principal or namespace fields. Specifically, when a user specifies a pattern like *-some-suffix in the principal or namespace field of a DENY rule, the wildcard suffix matching logic is not properly applied, causing the rule to never match and thus never deny access. This was identified in the Istio authorization engine's handling of TCP and HTTP filters [1][2].
Exploitation
An attacker can exploit this vulnerability by crafting requests that should be denied by a policy with a wildcard suffix. For example, if a policy denies all principals ending with -malicious, an attacker using a principal like user-malicious would not be blocked because the suffix match fails. The attack requires network access to a service protected by such a misconfigured AuthorizationPolicy. No special privileges are needed beyond the ability to send requests [1].
Impact
Successful exploitation allows an attacker to bypass intended access controls, gaining unauthorized access to protected services. Since the DENY rule is effectively ignored, any principal or namespace that should be denied based on a suffix pattern can instead reach the resource. This can lead to data exposure, privilege escalation, or other security breaches depending on the protected assets [2].
Mitigation
The issue has been fixed in Istio releases 1.5.9 and 1.6.8. Users are strongly advised to upgrade to these or later versions. For those unable to upgrade immediately, removing wildcard suffixes from DENY policies or using prefixes instead is a temporary workaround. The fix corrects the suffix matching logic to properly evaluate patterns like *-suffix [3].
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
istio.io/istioGo | >= 1.5.0, < 1.5.9 | 1.5.9 |
istio.io/istioGo | >= 1.6.0, < 1.6.8 | 1.6.8 |
Affected products
2- Istio/Istiodescription
Patches
272d2e135374f[release-1.5] fix authz suffix matching in TCP (#30)
8 files changed · +193 −41
pilot/pkg/security/authz/builder/testdata/v1beta1/action-deny-HTTP-for-TCP-filter-in.yaml+8 −8 modified@@ -53,13 +53,13 @@ spec: # rule[8] `from`: all fields, `to`: all fields, `when`: all fields. - from: - source: - principals: ["principal"] + principals: ["principal", "*principal-suffix", "principal-prefix*", "*"] requestPrincipals: ["requestPrincipals"] - namespaces: ["ns"] + namespaces: ["ns", "*ns-suffix", "ns-prefix*", "*"] ipBlocks: ["1.2.3.4"] - notPrincipals: ["not-principal"] + notPrincipals: ["not-principal", "*not-principal-suffix", "not-principal-prefix*", "*"] notRequestPrincipals: ["not-requestPrincipals"] - notNamespaces: ["not-ns"] + notNamespaces: ["not-ns", "*not-ns-suffix", "not-ns-prefix*", "*"] notIpBlocks: ["9.0.0.1"] to: - operation: @@ -79,11 +79,11 @@ spec: values: ["10.10.10.10"] notValues: ["90.10.10.10"] - key: "source.namespace" - values: ["ns"] - notValues: ["not-ns"] + values: ["ns", "*ns-suffix", "ns-prefix*", "*"] + notValues: ["not-ns", "*not-ns-suffix", "not-ns-prefix*", "*"] - key: "source.principal" - values: ["principal"] - notValues: ["not-principal"] + values: ["principal", "*principal-suffix", "principal-prefix*", "*"] + notValues: ["not-principal", "*not-principal-suffix", "not-principal-prefix*", "*"] - key: "request.auth.principal" values: ["requestPrincipals"] notValues: ["not-requestPrincipals"]
pilot/pkg/security/authz/builder/testdata/v1beta1/action-deny-HTTP-for-TCP-filter-out.yaml+112 −0 modified@@ -156,19 +156,60 @@ rules: - authenticated: principalName: exact: spiffe://principal + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: spiffe://.*principal-suffix + - authenticated: + principalName: + prefix: spiffe://principal-prefix + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .+ - notId: orIds: ids: - authenticated: principalName: exact: spiffe://not-principal + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: spiffe://.*not-principal-suffix + - authenticated: + principalName: + prefix: spiffe://not-principal-prefix + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .+ - orIds: ids: - authenticated: principalName: safeRegex: googleRe2: {} regex: .*/ns/ns/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*ns-suffix/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/ns-prefix.*/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*/.* - notId: orIds: ids: @@ -177,6 +218,21 @@ rules: safeRegex: googleRe2: {} regex: .*/ns/not-ns/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*not-ns-suffix/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/not-ns-prefix.*/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*/.* - orIds: ids: - sourceIp: @@ -206,6 +262,21 @@ rules: safeRegex: googleRe2: {} regex: .*/ns/ns/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*ns-suffix/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/ns-prefix.*/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*/.* - notId: orIds: ids: @@ -214,14 +285,55 @@ rules: safeRegex: googleRe2: {} regex: .*/ns/not-ns/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*not-ns-suffix/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/not-ns-prefix.*/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*/.* - orIds: ids: - authenticated: principalName: exact: spiffe://principal + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: spiffe://.*principal-suffix + - authenticated: + principalName: + prefix: spiffe://principal-prefix + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .+ - notId: orIds: ids: - authenticated: principalName: exact: spiffe://not-principal + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: spiffe://.*not-principal-suffix + - authenticated: + principalName: + prefix: spiffe://not-principal-prefix + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .+
pilot/pkg/security/authz/model/matcher/string.go+7 −4 modified@@ -52,11 +52,14 @@ func StringMatcherWithPrefix(v, prefix string, treatWildcardAsRequired bool) *en } return StringMatcherRegex(".*") case strings.HasPrefix(v, "*"): - return &envoy_matcher.StringMatcher{ - MatchPattern: &envoy_matcher.StringMatcher_Suffix{ - Suffix: prefix + strings.TrimPrefix(v, "*"), - }, + if prefix == "" { + return &envoy_matcher.StringMatcher{ + MatchPattern: &envoy_matcher.StringMatcher_Suffix{ + Suffix: strings.TrimPrefix(v, "*"), + }, + } } + return StringMatcherRegex(prefix + ".*" + strings.TrimPrefix(v, "*")) case strings.HasSuffix(v, "*"): return &envoy_matcher.StringMatcher{ MatchPattern: &envoy_matcher.StringMatcher_Prefix{
pilot/pkg/security/authz/model/matcher/string_test.go+23 −12 modified@@ -25,42 +25,53 @@ func TestStringMatcherWithPrefix(t *testing.T) { testCases := []struct { name string v string + prefix string treatWildcardAsRequired bool want *envoy_matcher.StringMatcher }{ { name: "wildcardAsRequired", v: "*", + prefix: "abc", treatWildcardAsRequired: true, want: StringMatcherRegex(".+"), }, { - name: "wildcard", - v: "*", - treatWildcardAsRequired: false, - want: StringMatcherRegex(".*"), + name: "wildcard", + v: "*", + prefix: "abc", + want: StringMatcherRegex(".*"), }, { - name: "prefix", - v: "-prefix-*", + name: "prefix", + v: "-prefix-*", + prefix: "abc", want: &envoy_matcher.StringMatcher{ MatchPattern: &envoy_matcher.StringMatcher_Prefix{ Prefix: "abc-prefix-", }, }, }, { - name: "suffix", - v: "*-suffix", + name: "suffix-empty-prefix", + v: "*-suffix", + prefix: "", want: &envoy_matcher.StringMatcher{ MatchPattern: &envoy_matcher.StringMatcher_Suffix{ - Suffix: "abc-suffix", + Suffix: "-suffix", }, }, }, { - name: "exact", - v: "-exact", + name: "suffix", + v: "*-suffix", + prefix: "abc", + want: StringMatcherRegex("abc.*-suffix"), + }, + { + name: "exact", + v: "-exact", + prefix: "abc", want: &envoy_matcher.StringMatcher{ MatchPattern: &envoy_matcher.StringMatcher_Exact{ Exact: "abc-exact", @@ -71,7 +82,7 @@ func TestStringMatcherWithPrefix(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := StringMatcherWithPrefix(tc.v, "abc", tc.treatWildcardAsRequired) + actual := StringMatcherWithPrefix(tc.v, tc.prefix, tc.treatWildcardAsRequired) if !reflect.DeepEqual(*actual, *tc.want) { t.Errorf("want %s but got %s", tc.want.String(), actual.String()) }
pilot/pkg/security/authz/model/principal.go+2 −4 modified@@ -253,15 +253,13 @@ func (principal *Principal) forKeyValue(key, value string, forTCPFilter bool) *e } return principalSourceIP(cidr) case attrSrcNamespace == key: + value = strings.Replace(value, "*", ".*", -1) + m := matcher.StringMatcherRegex(fmt.Sprintf(".*/ns/%s/.*", value)) if forTCPFilter { - regex := fmt.Sprintf(".*/ns/%s/.*", value) - m := matcher.StringMatcherRegex(regex) return principalAuthenticated(m) } // Proxy doesn't have attrSrcNamespace directly, but the information is encoded in attrSrcPrincipal // with format: cluster.local/ns/{NAMESPACE}/sa/{SERVICE-ACCOUNT}. - value = strings.Replace(value, "*", ".*", -1) - m := matcher.StringMatcherRegex(fmt.Sprintf(".*/ns/%s/.*", value)) metadata := matcher.MetadataStringMatcher(authn_model.AuthnFilterName, attrSrcPrincipal, m) return principalMetadata(metadata) case attrSrcPrincipal == key:
tests/integration/security/rbac_v1beta1_test.go+24 −11 modified@@ -684,10 +684,15 @@ func TestV1beta1_TCP(t *testing.T) { InstancePort: 8091, }, { - Name: "tcp", + Name: "tcp-8092", Protocol: protocol.TCP, InstancePort: 8092, }, + { + Name: "tcp-8093", + Protocol: protocol.TCP, + InstancePort: 8093, + }, } echoboot.NewBuilderOrFail(t, ctx). With(&x, util.EchoConfig("x", ns2, false, nil, g, p)). @@ -752,38 +757,46 @@ func TestV1beta1_TCP(t *testing.T) { // The policy on workload b denies request with path "/data" to port 8090: // - request to port http-8090 should be denied because both path and port are matched. // - request to port http-8091 should be allowed because the port is not matched. - // - request to port tcp should be allowed because the port is not matched. + // - request to port tcp-8092 should be allowed because the port is not matched. newTestCase(a, b, "http-8090", false), newTestCase(a, b, "http-8091", true), - newTestCase(a, b, "tcp", true), + newTestCase(a, b, "tcp-8092", true), // The policy on workload c denies request to port 8090: // - request to port http-8090 should be denied because the port is matched. // - request to http port 8091 should be allowed because the port is not matched. // - request to tcp port 8092 should be allowed because the port is not matched. + // - request from b to tcp port 8092 should be allowed by default. + // - request from b to tcp port 8093 should be denied because the principal is matched. + // - request from x to tcp port 8092 should be denied because the namespace is matched. + // - request from x to tcp port 8093 should be allowed by default. newTestCase(a, c, "http-8090", false), newTestCase(a, c, "http-8091", true), - newTestCase(a, c, "tcp", true), + newTestCase(a, c, "tcp-8092", true), + newTestCase(b, c, "tcp-8092", true), + newTestCase(b, c, "tcp-8093", false), + newTestCase(x, c, "tcp-8092", false), + newTestCase(x, c, "tcp-8093", true), // The policy on workload d denies request from service account a and workloads in namespace 2: // - request from a to d should be denied because it has service account a. // - request from b to d should be allowed. // - request from c to d should be allowed. // - request from x to a should be allowed because there is no policy on a. // - request from x to d should be denied because it's in namespace 2. - newTestCase(a, d, "tcp", false), - newTestCase(b, d, "tcp", true), - newTestCase(c, d, "tcp", true), - newTestCase(x, a, "tcp", true), - newTestCase(x, d, "tcp", false), + newTestCase(a, d, "tcp-8092", false), + newTestCase(b, d, "tcp-8092", true), + newTestCase(c, d, "tcp-8092", true), + newTestCase(x, a, "tcp-8092", true), + newTestCase(x, d, "tcp-8092", false), // The policy on workload e denies request with path "/other": // - request to port http-8090 should be allowed because the path is not matched. // - request to port http-8091 should be allowed because the path is not matched. - // - request to port tcp should be denied because policy uses HTTP fields. + // - request to port tcp-8092 should be denied because policy uses HTTP fields. newTestCase(a, e, "http-8090", true), newTestCase(a, e, "http-8091", true), - newTestCase(a, e, "tcp", false), + newTestCase(a, e, "tcp-8092", false), } rbacUtil.RunRBACTest(t, cases)
tests/integration/security/testdata/rbac/v1beta1-tcp.yaml.tmpl+16 −1 modified@@ -17,7 +17,10 @@ spec: ports: ["8090"] --- -# The following policy denies request to port 8090 for workload c +# The following policy denies: +# request to port 8090 for workload c +# request to port 8093 with principal suffix matching +# request to port 8092 with namespace suffix matching apiVersion: "security.istio.io/v1beta1" kind: AuthorizationPolicy @@ -33,6 +36,18 @@ spec: - to: - operation: ports: ["8090"] + - to: + - operation: + ports: ["8093"] + from: + - source: + principals: ["*/ns/{{ .Namespace }}/sa/b"] + - to: + - operation: + ports: ["8092"] + from: + - source: + namespaces: ["*{{ .Namespace2 }}"] --- # The following policy denies request from service account a and namespace 2 for workload d
tests/integration/security/util/rbac_util/util.go+1 −1 modified@@ -73,7 +73,7 @@ func (tc TestCase) CheckRBACRequest() error { return getError(req, "allow with code 200", fmt.Sprintf("error: %v", err)) } } else { - if req.Options.PortName == "tcp" || req.Options.PortName == "grpc" { + if strings.HasPrefix(req.Options.PortName, "tcp") || req.Options.PortName == "grpc" { expectedErrMsg := "EOF" // TCP deny message. if req.Options.PortName == "grpc" { expectedErrMsg = "rpc error: code = PermissionDenied desc = RBAC: access denied"
4c73414556b8fix authz suffix matching in TCP (#29)
7 files changed · +168 −31
pilot/pkg/security/authz/builder/testdata/action-deny-HTTP-for-TCP-filter-in.yaml+8 −8 modified@@ -53,13 +53,13 @@ spec: # rule[8] `from`: all fields, `to`: all fields, `when`: all fields. - from: - source: - principals: ["principal"] + principals: ["principal", "*principal-suffix", "principal-prefix*", "*"] requestPrincipals: ["requestPrincipals"] - namespaces: ["ns"] + namespaces: ["ns", "*ns-suffix", "ns-prefix*", "*"] ipBlocks: ["1.2.3.4"] - notPrincipals: ["not-principal"] + notPrincipals: ["not-principal", "*not-principal-suffix", "not-principal-prefix*", "*"] notRequestPrincipals: ["not-requestPrincipals"] - notNamespaces: ["not-ns"] + notNamespaces: ["not-ns", "*not-ns-suffix", "not-ns-prefix*", "*"] notIpBlocks: ["9.0.0.1"] to: - operation: @@ -79,11 +79,11 @@ spec: values: ["10.10.10.10"] notValues: ["90.10.10.10"] - key: "source.namespace" - values: ["ns"] - notValues: ["not-ns"] + values: ["ns", "*ns-suffix", "ns-prefix*", "*"] + notValues: ["not-ns", "*not-ns-suffix", "not-ns-prefix*", "*"] - key: "source.principal" - values: ["principal"] - notValues: ["not-principal"] + values: ["principal", "*principal-suffix", "principal-prefix*", "*"] + notValues: ["not-principal", "*not-principal-suffix", "not-principal-prefix*", "*"] - key: "request.auth.principal" values: ["requestPrincipals"] notValues: ["not-requestPrincipals"]
pilot/pkg/security/authz/builder/testdata/action-deny-HTTP-for-TCP-filter-out.yaml+112 −0 modified@@ -159,19 +159,60 @@ typedConfig: - authenticated: principalName: exact: spiffe://principal + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: spiffe://.*principal-suffix + - authenticated: + principalName: + prefix: spiffe://principal-prefix + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .+ - notId: orIds: ids: - authenticated: principalName: exact: spiffe://not-principal + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: spiffe://.*not-principal-suffix + - authenticated: + principalName: + prefix: spiffe://not-principal-prefix + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .+ - orIds: ids: - authenticated: principalName: safeRegex: googleRe2: {} regex: .*/ns/ns/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*ns-suffix/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/ns-prefix.*/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*/.* - notId: orIds: ids: @@ -180,6 +221,21 @@ typedConfig: safeRegex: googleRe2: {} regex: .*/ns/not-ns/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*not-ns-suffix/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/not-ns-prefix.*/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*/.* - orIds: ids: - sourceIp: @@ -209,6 +265,21 @@ typedConfig: safeRegex: googleRe2: {} regex: .*/ns/ns/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*ns-suffix/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/ns-prefix.*/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*/.* - notId: orIds: ids: @@ -217,15 +288,56 @@ typedConfig: safeRegex: googleRe2: {} regex: .*/ns/not-ns/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*not-ns-suffix/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/not-ns-prefix.*/.* + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .*/ns/.*/.* - orIds: ids: - authenticated: principalName: exact: spiffe://principal + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: spiffe://.*principal-suffix + - authenticated: + principalName: + prefix: spiffe://principal-prefix + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .+ - notId: orIds: ids: - authenticated: principalName: exact: spiffe://not-principal + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: spiffe://.*not-principal-suffix + - authenticated: + principalName: + prefix: spiffe://not-principal-prefix + - authenticated: + principalName: + safeRegex: + googleRe2: {} + regex: .+ statPrefix: tcp.
pilot/pkg/security/authz/matcher/string.go+7 −4 modified@@ -49,11 +49,14 @@ func StringMatcherWithPrefix(v, prefix string) *matcherpb.StringMatcher { case v == "*": return StringMatcherRegex(".+") case strings.HasPrefix(v, "*"): - return &matcherpb.StringMatcher{ - MatchPattern: &matcherpb.StringMatcher_Suffix{ - Suffix: prefix + strings.TrimPrefix(v, "*"), - }, + if prefix == "" { + return &matcherpb.StringMatcher{ + MatchPattern: &matcherpb.StringMatcher_Suffix{ + Suffix: strings.TrimPrefix(v, "*"), + }, + } } + return StringMatcherRegex(prefix + ".*" + strings.TrimPrefix(v, "*")) case strings.HasSuffix(v, "*"): return &matcherpb.StringMatcher{ MatchPattern: &matcherpb.StringMatcher_Prefix{
pilot/pkg/security/authz/matcher/string_test.go+25 −14 modified@@ -23,36 +23,47 @@ import ( func TestStringMatcherWithPrefix(t *testing.T) { testCases := []struct { - name string - v string - want *matcherpb.StringMatcher + name string + v string + prefix string + want *matcherpb.StringMatcher }{ { - name: "wildcardAsRequired", - v: "*", - want: StringMatcherRegex(".+"), + name: "wildcardAsRequired", + v: "*", + prefix: "abc", + want: StringMatcherRegex(".+"), }, { - name: "prefix", - v: "-prefix-*", + name: "prefix", + v: "-prefix-*", + prefix: "abc", want: &matcherpb.StringMatcher{ MatchPattern: &matcherpb.StringMatcher_Prefix{ Prefix: "abc-prefix-", }, }, }, { - name: "suffix", - v: "*-suffix", + name: "suffix-empty-prefix", + v: "*-suffix", + prefix: "", want: &matcherpb.StringMatcher{ MatchPattern: &matcherpb.StringMatcher_Suffix{ - Suffix: "abc-suffix", + Suffix: "-suffix", }, }, }, { - name: "exact", - v: "-exact", + name: "suffix", + v: "*-suffix", + prefix: "abc", + want: StringMatcherRegex("abc.*-suffix"), + }, + { + name: "exact", + v: "-exact", + prefix: "abc", want: &matcherpb.StringMatcher{ MatchPattern: &matcherpb.StringMatcher_Exact{ Exact: "abc-exact", @@ -63,7 +74,7 @@ func TestStringMatcherWithPrefix(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - actual := StringMatcherWithPrefix(tc.v, "abc") + actual := StringMatcherWithPrefix(tc.v, tc.prefix) if !reflect.DeepEqual(*actual, *tc.want) { t.Errorf("want %s but got %s", tc.want.String(), actual.String()) }
pilot/pkg/security/authz/model/generator.go+2 −4 modified@@ -116,15 +116,13 @@ func (srcNamespaceGenerator) permission(_, _ string, _ bool) (*rbacpb.Permission } func (srcNamespaceGenerator) principal(_, value string, forTCP bool) (*rbacpb.Principal, error) { + v := strings.Replace(value, "*", ".*", -1) + m := matcher.StringMatcherRegex(fmt.Sprintf(".*/ns/%s/.*", v)) if forTCP { - regex := fmt.Sprintf(".*/ns/%s/.*", value) - m := matcher.StringMatcherRegex(regex) return principalAuthenticated(m), nil } // Proxy doesn't have attrSrcNamespace directly, but the information is encoded in attrSrcPrincipal // with format: cluster.local/ns/{NAMESPACE}/sa/{SERVICE-ACCOUNT}. - v := strings.Replace(value, "*", ".*", -1) - m := matcher.StringMatcherRegex(fmt.Sprintf(".*/ns/%s/.*", v)) metadata := matcher.MetadataStringMatcher(sm.AuthnFilterName, attrSrcPrincipal, m) return principalMetadata(metadata), nil }
tests/integration/security/authorization_test.go+8 −0 modified@@ -715,9 +715,17 @@ func TestAuthorization_TCP(t *testing.T) { // - request to port http-8090 should be denied because the port is matched. // - request to http port 8091 should be allowed because the port is not matched. // - request to tcp port 8092 should be allowed because the port is not matched. + // - request from b should be denied because the principal is matched + // - request from x should be denied because the namespace is matched newTestCase(a, c, "http-8090", false, scheme.HTTP), newTestCase(a, c, "http-8091", true, scheme.HTTP), newTestCase(a, c, "tcp", true, scheme.TCP), + newTestCase(b, c, "http-8090", false, scheme.HTTP), + newTestCase(b, c, "http-8091", false, scheme.HTTP), + newTestCase(b, c, "tcp", false, scheme.TCP), + newTestCase(x, c, "http-8090", false, scheme.HTTP), + newTestCase(x, c, "http-8091", false, scheme.HTTP), + newTestCase(x, c, "tcp", false, scheme.TCP), // The policy on workload d denies request from service account a and workloads in namespace 2: // - request from a to d should be denied because it has service account a.
tests/integration/security/testdata/authz/v1beta1-tcp.yaml.tmpl+6 −1 modified@@ -17,7 +17,7 @@ spec: ports: ["8090"] --- -# The following policy denies request to port 8090 for workload c +# The following policy denies request to port 8090 for workload c, requests from principal of suffix "b" or namespace of suffix Namespace2 apiVersion: "security.istio.io/v1beta1" kind: AuthorizationPolicy @@ -33,6 +33,11 @@ spec: - to: - operation: ports: ["8090"] + - from: + - source: + principals: ["*b"] + - source: + namespaces: ["*{{ .Namespace2 }}"] --- # The following policy denies request from service account a and namespace 2 for workload d
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
10- github.com/advisories/GHSA-82mm-ffjr-h86cghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-16844ghsaADVISORY
- github.com/istio/istio/commit/4c73414556b83f0e75c1b3a0a89a23103a71573cghsaWEB
- github.com/istio/istio/commit/72d2e135374f421b656d6f1a21f474db46134aceghsaWEB
- github.com/istio/istio/releases/tag/1.5.9ghsaWEB
- github.com/istio/istio/releases/tag/1.6.8ghsaWEB
- istio.io/latest/news/releases/1.5.x/announcing-1.5.9ghsaWEB
- istio.io/latest/news/releases/1.6.x/announcing-1.6.8ghsaWEB
- istio.io/latest/news/security/istio-security-2020-009ghsaWEB
- istio.io/latest/news/security/istio-security-2020-009/mitrex_refsource_CONFIRM
News mentions
0No linked articles in our index yet.