High severityNVD Advisory· Published Nov 6, 2025· Updated Apr 15, 2026
CVE-2025-64171
CVE-2025-64171
Description
MARIN3R is a lightweight, CRD based envoy control plane for kubernetes. In versions 0.13.3 and below, there is a cross-namespace secret access vulnerability in the project's DiscoveryServiceCertificate which allows users to bypass RBAC and access secrets in unauthorized namespaces. This issue is fixed in version 0.13.4.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
github.com/3scale-sre/marin3rGo | < 0.13.4 | 0.13.4 |
Affected products
1Patches
2c60246a43ae8Merge pull request #294 from 3scale-sre/fix/cross-namespace-access
2 files changed · +121 −1
internal/pkg/reconcilers/operator/discoveryservicecertificate/providers/marin3r/crud.go+17 −1 modified@@ -210,10 +210,26 @@ func (cp *CertificateProvider) VerifyCertificate(ctx context.Context) error { // getIssuerCertificate returns the issuer certificate for a DiscoveryServiceCertificate resource func (cp *CertificateProvider) getIssuerCertificate(ctx context.Context) (*x509.Certificate, interface{}, error) { if cp.dsc.Spec.Signer.CASigned != nil { + caNamespace := cp.dsc.Spec.Signer.CASigned.SecretRef.Namespace + dscNamespace := cp.dsc.GetNamespace() + + // Default to current namespace if not specified + if caNamespace == "" { + caNamespace = dscNamespace + } + + // Enforce same-namespace requirement for security + if caNamespace != dscNamespace { + return nil, nil, fmt.Errorf( + "DiscoveryServiceCertificate cannot reference Secrets in other namespaces: "+ + "caSecretRef is in namespace '%s' but DiscoveryServiceCertificate is in '%s'", + caNamespace, dscNamespace) + } + secret := &corev1.Secret{} key := types.NamespacedName{ Name: cp.dsc.Spec.Signer.CASigned.SecretRef.Name, - Namespace: cp.dsc.Spec.Signer.CASigned.SecretRef.Namespace, + Namespace: caNamespace, } if err := cp.client.Get(ctx, key, secret); err != nil {
internal/pkg/reconcilers/operator/discoveryservicecertificate/providers/marin3r/crud_test.go+104 −0 modified@@ -442,6 +442,38 @@ func TestCertificateProvider_VerifyCertificate(t *testing.T) { }}}, wantErr: true, }, + { + name: "Verify returns an error when issuer is in different namespace", + fields: fields{ + ctx: context.TODO(), + logger: ctrl.Log.WithName("test"), + client: fake.NewClientBuilder().WithScheme(s).WithObjects( + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "issuer", Namespace: "other-namespace"}, + Data: map[string][]byte{ + tlsCertificateKey: test.TestIssuerCertificate(), + tlsPrivateKeyKey: test.TestIssuerKey(), + }}, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "secret", Namespace: "test"}, + Data: map[string][]byte{ + tlsCertificateKey: test.TestValidCertificate(), + tlsPrivateKeyKey: []byte("xxxx"), + }}, + ).Build(), + scheme: s, + dsc: &operatorv1alpha1.DiscoveryServiceCertificate{ + ObjectMeta: metav1.ObjectMeta{Name: "dsc", Namespace: "test"}, + Spec: operatorv1alpha1.DiscoveryServiceCertificateSpec{ + Signer: operatorv1alpha1.DiscoveryServiceCertificateSigner{ + CASigned: &operatorv1alpha1.CASignedConfig{ + SecretRef: corev1.SecretReference{Name: "issuer", Namespace: "other-namespace"}, + }, + }, + SecretRef: corev1.SecretReference{Name: "secret"}, + }}}, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -538,6 +570,78 @@ func TestCertificateProvider_getIssuerCertificate(t *testing.T) { want1: nil, wantErr: true, }, + { + name: "Returns an error when attempting to access Secret in different namespace", + fields: fields{ + ctx: context.TODO(), + logger: ctrl.Log.WithName("test"), + client: fake.NewClientBuilder().WithScheme(s).WithObjects( + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "issuer", Namespace: "other-namespace"}, + Type: corev1.SecretTypeTLS, + Data: map[string][]byte{ + tlsCertificateKey: test.TestIssuerCertificate(), + tlsPrivateKeyKey: test.TestIssuerKey(), + }, + }).Build(), + scheme: s, + dsc: &operatorv1alpha1.DiscoveryServiceCertificate{ + ObjectMeta: metav1.ObjectMeta{Name: "dsc", Namespace: "test"}, + Spec: operatorv1alpha1.DiscoveryServiceCertificateSpec{ + CommonName: "test", + ValidFor: 3600, + Hosts: []string{"example.test"}, + Signer: operatorv1alpha1.DiscoveryServiceCertificateSigner{ + CASigned: &operatorv1alpha1.CASignedConfig{ + SecretRef: corev1.SecretReference{Name: "issuer", Namespace: "other-namespace"}, + }, + }, + SecretRef: corev1.SecretReference{Name: "secret"}, + }}}, + want: nil, + want1: nil, + wantErr: true, + }, + { + name: "Allows access when caSecretRef namespace is empty (defaults to same namespace)", + fields: fields{ + ctx: context.TODO(), + logger: ctrl.Log.WithName("test"), + client: fake.NewClientBuilder().WithScheme(s).WithObjects( + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "issuer", Namespace: "test"}, + Type: corev1.SecretTypeTLS, + Data: map[string][]byte{ + tlsCertificateKey: test.TestIssuerCertificate(), + tlsPrivateKeyKey: test.TestIssuerKey(), + }, + }).Build(), + scheme: s, + dsc: &operatorv1alpha1.DiscoveryServiceCertificate{ + ObjectMeta: metav1.ObjectMeta{Name: "dsc", Namespace: "test"}, + Spec: operatorv1alpha1.DiscoveryServiceCertificateSpec{ + CommonName: "test", + ValidFor: 3600, + Hosts: []string{"example.test"}, + Signer: operatorv1alpha1.DiscoveryServiceCertificateSigner{ + CASigned: &operatorv1alpha1.CASignedConfig{ + SecretRef: corev1.SecretReference{Name: "issuer", Namespace: ""}, + }, + }, + SecretRef: corev1.SecretReference{Name: "secret"}, + }}}, + want: func() *x509.Certificate { + cert, _ := pki.LoadX509Certificate(test.TestIssuerCertificate()) + + return cert + }(), + want1: func() interface{} { + signer, _ := pki.DecodePrivateKeyBytes(test.TestIssuerKey()) + + return signer + }(), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {
859b14115fdeDon't allow cross namespace Secrets access
2 files changed · +121 −1
internal/pkg/reconcilers/operator/discoveryservicecertificate/providers/marin3r/crud.go+17 −1 modified@@ -210,10 +210,26 @@ func (cp *CertificateProvider) VerifyCertificate(ctx context.Context) error { // getIssuerCertificate returns the issuer certificate for a DiscoveryServiceCertificate resource func (cp *CertificateProvider) getIssuerCertificate(ctx context.Context) (*x509.Certificate, interface{}, error) { if cp.dsc.Spec.Signer.CASigned != nil { + caNamespace := cp.dsc.Spec.Signer.CASigned.SecretRef.Namespace + dscNamespace := cp.dsc.GetNamespace() + + // Default to current namespace if not specified + if caNamespace == "" { + caNamespace = dscNamespace + } + + // Enforce same-namespace requirement for security + if caNamespace != dscNamespace { + return nil, nil, fmt.Errorf( + "DiscoveryServiceCertificate cannot reference Secrets in other namespaces: "+ + "caSecretRef is in namespace '%s' but DiscoveryServiceCertificate is in '%s'", + caNamespace, dscNamespace) + } + secret := &corev1.Secret{} key := types.NamespacedName{ Name: cp.dsc.Spec.Signer.CASigned.SecretRef.Name, - Namespace: cp.dsc.Spec.Signer.CASigned.SecretRef.Namespace, + Namespace: caNamespace, } if err := cp.client.Get(ctx, key, secret); err != nil {
internal/pkg/reconcilers/operator/discoveryservicecertificate/providers/marin3r/crud_test.go+104 −0 modified@@ -442,6 +442,38 @@ func TestCertificateProvider_VerifyCertificate(t *testing.T) { }}}, wantErr: true, }, + { + name: "Verify returns an error when issuer is in different namespace", + fields: fields{ + ctx: context.TODO(), + logger: ctrl.Log.WithName("test"), + client: fake.NewClientBuilder().WithScheme(s).WithObjects( + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "issuer", Namespace: "other-namespace"}, + Data: map[string][]byte{ + tlsCertificateKey: test.TestIssuerCertificate(), + tlsPrivateKeyKey: test.TestIssuerKey(), + }}, + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "secret", Namespace: "test"}, + Data: map[string][]byte{ + tlsCertificateKey: test.TestValidCertificate(), + tlsPrivateKeyKey: []byte("xxxx"), + }}, + ).Build(), + scheme: s, + dsc: &operatorv1alpha1.DiscoveryServiceCertificate{ + ObjectMeta: metav1.ObjectMeta{Name: "dsc", Namespace: "test"}, + Spec: operatorv1alpha1.DiscoveryServiceCertificateSpec{ + Signer: operatorv1alpha1.DiscoveryServiceCertificateSigner{ + CASigned: &operatorv1alpha1.CASignedConfig{ + SecretRef: corev1.SecretReference{Name: "issuer", Namespace: "other-namespace"}, + }, + }, + SecretRef: corev1.SecretReference{Name: "secret"}, + }}}, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -538,6 +570,78 @@ func TestCertificateProvider_getIssuerCertificate(t *testing.T) { want1: nil, wantErr: true, }, + { + name: "Returns an error when attempting to access Secret in different namespace", + fields: fields{ + ctx: context.TODO(), + logger: ctrl.Log.WithName("test"), + client: fake.NewClientBuilder().WithScheme(s).WithObjects( + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "issuer", Namespace: "other-namespace"}, + Type: corev1.SecretTypeTLS, + Data: map[string][]byte{ + tlsCertificateKey: test.TestIssuerCertificate(), + tlsPrivateKeyKey: test.TestIssuerKey(), + }, + }).Build(), + scheme: s, + dsc: &operatorv1alpha1.DiscoveryServiceCertificate{ + ObjectMeta: metav1.ObjectMeta{Name: "dsc", Namespace: "test"}, + Spec: operatorv1alpha1.DiscoveryServiceCertificateSpec{ + CommonName: "test", + ValidFor: 3600, + Hosts: []string{"example.test"}, + Signer: operatorv1alpha1.DiscoveryServiceCertificateSigner{ + CASigned: &operatorv1alpha1.CASignedConfig{ + SecretRef: corev1.SecretReference{Name: "issuer", Namespace: "other-namespace"}, + }, + }, + SecretRef: corev1.SecretReference{Name: "secret"}, + }}}, + want: nil, + want1: nil, + wantErr: true, + }, + { + name: "Allows access when caSecretRef namespace is empty (defaults to same namespace)", + fields: fields{ + ctx: context.TODO(), + logger: ctrl.Log.WithName("test"), + client: fake.NewClientBuilder().WithScheme(s).WithObjects( + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "issuer", Namespace: "test"}, + Type: corev1.SecretTypeTLS, + Data: map[string][]byte{ + tlsCertificateKey: test.TestIssuerCertificate(), + tlsPrivateKeyKey: test.TestIssuerKey(), + }, + }).Build(), + scheme: s, + dsc: &operatorv1alpha1.DiscoveryServiceCertificate{ + ObjectMeta: metav1.ObjectMeta{Name: "dsc", Namespace: "test"}, + Spec: operatorv1alpha1.DiscoveryServiceCertificateSpec{ + CommonName: "test", + ValidFor: 3600, + Hosts: []string{"example.test"}, + Signer: operatorv1alpha1.DiscoveryServiceCertificateSigner{ + CASigned: &operatorv1alpha1.CASignedConfig{ + SecretRef: corev1.SecretReference{Name: "issuer", Namespace: ""}, + }, + }, + SecretRef: corev1.SecretReference{Name: "secret"}, + }}}, + want: func() *x509.Certificate { + cert, _ := pki.LoadX509Certificate(test.TestIssuerCertificate()) + + return cert + }(), + want1: func() interface{} { + signer, _ := pki.DecodePrivateKeyBytes(test.TestIssuerKey()) + + return signer + }(), + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-gf93-xccm-5g6jghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-64171ghsaADVISORY
- github.com/3scale-sre/marin3r/commit/859b14115fde1d67620e645cd1b62e90e30d9981nvdWEB
- github.com/3scale-sre/marin3r/commit/c60246a43ae8c0c38dd7267f298d68a121a159faghsaWEB
- github.com/3scale-sre/marin3r/pull/294ghsaWEB
- github.com/3scale-sre/marin3r/security/advisories/GHSA-gf93-xccm-5g6jnvdWEB
News mentions
0No linked articles in our index yet.