VYPR
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.

PackageAffected versionsPatched versions
github.com/3scale-sre/marin3rGo
< 0.13.40.13.4

Affected products

1

Patches

2
c60246a43ae8

Merge pull request #294 from 3scale-sre/fix/cross-namespace-access

https://github.com/3scale-sre/marin3r3scale Prow RobotNov 3, 2025via ghsa
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) {
    
859b14115fde

Don't allow cross namespace Secrets access

https://github.com/3scale-sre/marin3rRoi VazquezOct 31, 2025via ghsa
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

News mentions

0

No linked articles in our index yet.