VYPR
Medium severity6.4NVD Advisory· Published Apr 30, 2026· Updated May 1, 2026

CVE-2026-41174

CVE-2026-41174

Description

Traefik is an HTTP reverse proxy and load balancer. Prior to versions 2.11.43, 3.6.14, and 3.7.0-rc.2, there is a potential vulnerability in Traefik's Kubernetes CRD provider cross-namespace isolation enforcement. When providers.kubernetesCRD.allowCrossNamespace=false, Traefik correctly rejects direct cross-namespace middleware references from IngressRoute objects, but fails to apply the same restriction to middleware references nested inside a Chain middleware's spec.chain.middlewares[]. An actor with permission to create or update Traefik CRDs in their own namespace can exploit this to cause Traefik to resolve and apply middleware objects from another namespace, bypassing the documented isolation boundary. This issue has been patched in versions 2.11.43, 3.6.14, and 3.7.0-rc.2.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
github.com/traefik/traefik/v3Go
>= 3.7.0-ea.1, < 3.7.0-rc.23.7.0-rc.2
github.com/traefik/traefik/v3Go
>= 3.0.0-beta1, < 3.6.143.6.14
github.com/traefik/traefik/v2Go
< 2.11.432.11.43
github.com/traefik/traefikGo
<= 1.7.34

Affected products

5
  • Traefik/Traefik5 versions
    cpe:2.3:a:traefik:traefik:*:*:*:*:*:*:*:*+ 4 more
    • cpe:2.3:a:traefik:traefik:*:*:*:*:*:*:*:*range: <2.11.43
    • cpe:2.3:a:traefik:traefik:3.7.0:ea1:*:*:*:*:*:*
    • cpe:2.3:a:traefik:traefik:3.7.0:ea2:*:*:*:*:*:*
    • cpe:2.3:a:traefik:traefik:3.7.0:ea3:*:*:*:*:*:*
    • cpe:2.3:a:traefik:traefik:3.7.0:rc1:*:*:*:*:*:*

Patches

1
df00d82fc7f1

Honor allowCrossNamespace with chain middleware CRD

https://github.com/traefik/traefikRomainApr 15, 2026via ghsa
5 files changed · +129 9
  • docs/content/migration/v2.md+10 0 modified
    @@ -785,3 +785,13 @@ The default value for this option is -1, which means there is no limit to the re
     However, it is strongly recommended to set this option to a suitable value to avoid performance issues such as memory exhaustion.
     
     Please check out the [HTTP](../providers/http.md#maxresponsebodysize) provider documentation for more details.
    +
    +## v2.11.43
    +
    +### Kubernetes CRD: Chain middleware and `allowCrossNamespace`
    +
    +In `v2.11.43`, the `Chain` middleware now honors the Kubernetes CRD provider's `allowCrossNamespace` option.
    +Previously, a `Chain` could reference middlewares in other namespaces regardless of the `allowCrossNamespace` configuration.
    +
    +If `allowCrossNamespace` is set to `false` (the default) and a `Chain` middleware references a middleware in a different namespace from its own,
    +the whole `Chain` is now rejected and an error is logged.
    
  • pkg/provider/kubernetes/crd/fixtures/with_middleware_cross_namespace.yml+35 0 modified
    @@ -37,6 +37,16 @@ spec:
           port: 80
         middlewares:
         - name: cross-ns-stripprefix@kubernetescrd
    +  - match: Host(`foo.com`) && PathPrefix(`/chain`)
    +    kind: Rule
    +    priority: 12
    +    services:
    +    - name: whoami
    +      namespace: default
    +      port: 80
    +    middlewares:
    +    - name: test-chain
    +    - name: test-chain-cross-provider
     
     ---
     apiVersion: traefik.io/v1alpha1
    @@ -50,6 +60,31 @@ spec:
         prefixes:
           - /stripit
     
    +---
    +apiVersion: traefik.io/v1alpha1
    +kind: Middleware
    +metadata:
    +  name: test-chain
    +  namespace: default
    +
    +spec:
    +  chain:
    +    middlewares:
    +      - name: stripprefix
    +        namespace: cross-ns
    +
    +---
    +apiVersion: traefik.io/v1alpha1
    +kind: Middleware
    +metadata:
    +  name: test-chain-cross-provider
    +  namespace: default
    +
    +spec:
    +  chain:
    +    middlewares:
    +      - name: other-middleware@kubernetescrd
    +
     ---
     apiVersion: traefik.io/v1alpha1
     kind: Middleware
    
  • pkg/provider/kubernetes/crd/kubernetes.go+26 7 modified
    @@ -279,13 +279,19 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
     			continue
     		}
     
    +		chain, err := createChainMiddleware(ctxMid, middleware.Namespace, middleware.Spec.Chain, p.AllowCrossNamespace)
    +		if err != nil {
    +			log.FromContext(ctxMid).Errorf("Error while reading chain middleware: %v", err)
    +			continue
    +		}
    +
     		conf.HTTP.Middlewares[id] = &dynamic.Middleware{
     			AddPrefix:         middleware.Spec.AddPrefix,
     			StripPrefix:       middleware.Spec.StripPrefix,
     			StripPrefixRegex:  middleware.Spec.StripPrefixRegex,
     			ReplacePath:       middleware.Spec.ReplacePath,
     			ReplacePathRegex:  middleware.Spec.ReplacePathRegex,
    -			Chain:             createChainMiddleware(ctxMid, middleware.Namespace, middleware.Spec.Chain),
    +			Chain:             chain,
     			IPWhiteList:       middleware.Spec.IPWhiteList,
     			IPAllowList:       middleware.Spec.IPAllowList,
     			Headers:           middleware.Spec.Headers,
    @@ -854,13 +860,20 @@ func loadAuthCredentials(secret *corev1.Secret) ([]string, error) {
     	return credentials, nil
     }
     
    -func createChainMiddleware(ctx context.Context, namespace string, chain *traefikv1alpha1.Chain) *dynamic.Chain {
    +func createChainMiddleware(ctx context.Context, parentNamespace string, chain *traefikv1alpha1.Chain, allowCrossNamespace bool) (*dynamic.Chain, error) {
     	if chain == nil {
    -		return nil
    +		return nil, nil
     	}
     
     	var mds []string
     	for _, mi := range chain.Middlewares {
    +		if !allowCrossNamespace && strings.HasSuffix(mi.Name, providerNamespaceSeparator+providerName) {
    +			// Since we are not able to know if another namespace is in the name (namespace-name@kubernetescrd),
    +			// if the provider namespace kubernetescrd is used,
    +			// we don't allow this format to avoid cross-namespace references.
    +			return nil, fmt.Errorf("invalid reference to middleware %s: when allowCrossNamespace is disabled @kubernetescrd provider references are disallowed", mi.Name)
    +		}
    +
     		if strings.Contains(mi.Name, providerNamespaceSeparator) {
     			if len(mi.Namespace) > 0 {
     				log.FromContext(ctx).
    @@ -870,13 +883,19 @@ func createChainMiddleware(ctx context.Context, namespace string, chain *traefik
     			continue
     		}
     
    -		ns := mi.Namespace
    -		if len(ns) == 0 {
    -			ns = namespace
    +		ns := parentNamespace
    +		if len(mi.Namespace) > 0 {
    +			if !isNamespaceAllowed(allowCrossNamespace, parentNamespace, mi.Namespace) {
    +				return nil, fmt.Errorf("middleware %s/%s is not in the chain namespace %s", mi.Namespace, mi.Name, parentNamespace)
    +			}
    +
    +			ns = mi.Namespace
     		}
    +
     		mds = append(mds, makeID(ns, mi.Name))
     	}
    -	return &dynamic.Chain{Middlewares: mds}
    +
    +	return &dynamic.Chain{Middlewares: mds}, nil
     }
     
     func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options {
    
  • pkg/provider/kubernetes/crd/kubernetes_http.go+2 2 modified
    @@ -166,8 +166,8 @@ func (p *Provider) makeMiddlewareKeys(ctx context.Context, ingRouteNamespace str
     		if !p.AllowCrossNamespace && strings.HasSuffix(mi.Name, providerNamespaceSeparator+providerName) {
     			// Since we are not able to know if another namespace is in the name (namespace-name@kubernetescrd),
     			// if the provider namespace kubernetescrd is used,
    -			// we don't allow this format to avoid cross namespace references.
    -			return nil, fmt.Errorf("invalid reference to middleware %s: with crossnamespace disallowed, the namespace field needs to be explicitly specified", mi.Name)
    +			// we don't allow this format to avoid cross-namespace references.
    +			return nil, fmt.Errorf("invalid reference to middleware %s: when allowCrossNamespace is disabled @kubernetescrd provider references are disallowed", mi.Name)
     		}
     
     		if strings.Contains(name, providerNamespaceSeparator) {
    
  • pkg/provider/kubernetes/crd/kubernetes_test.go+56 0 modified
    @@ -5074,6 +5074,16 @@ func TestCrossNamespace(t *testing.T) {
     							Priority:    12,
     							Middlewares: []string{"default-test-errorpage"},
     						},
    +						"default-test-crossnamespace-route-4932ffbbcd99474df323": {
    +							EntryPoints: []string{"foo"},
    +							Service:     "default-test-crossnamespace-route-4932ffbbcd99474df323",
    +							Rule:        "Host(`foo.com`) && PathPrefix(`/chain`)",
    +							Priority:    12,
    +							Middlewares: []string{
    +								"default-test-chain",
    +								"default-test-chain-cross-provider",
    +							},
    +						},
     					},
     					Middlewares: map[string]*dynamic.Middleware{
     						"cross-ns-stripprefix": {
    @@ -5097,6 +5107,19 @@ func TestCrossNamespace(t *testing.T) {
     								PassHostHeader: pointer(true),
     							},
     						},
    +						"default-test-crossnamespace-route-4932ffbbcd99474df323": {
    +							LoadBalancer: &dynamic.ServersLoadBalancer{
    +								Servers: []dynamic.Server{
    +									{
    +										URL: "http://10.10.0.1:80",
    +									},
    +									{
    +										URL: "http://10.10.0.2:80",
    +									},
    +								},
    +								PassHostHeader: pointer(true),
    +							},
    +						},
     					},
     					ServersTransports: map[string]*dynamic.ServersTransport{},
     				},
    @@ -5142,6 +5165,16 @@ func TestCrossNamespace(t *testing.T) {
     							Priority:    12,
     							Middlewares: []string{"cross-ns-stripprefix@kubernetescrd"},
     						},
    +						"default-test-crossnamespace-route-4932ffbbcd99474df323": {
    +							EntryPoints: []string{"foo"},
    +							Service:     "default-test-crossnamespace-route-4932ffbbcd99474df323",
    +							Rule:        "Host(`foo.com`) && PathPrefix(`/chain`)",
    +							Priority:    12,
    +							Middlewares: []string{
    +								"default-test-chain",
    +								"default-test-chain-cross-provider",
    +							},
    +						},
     					},
     					Middlewares: map[string]*dynamic.Middleware{
     						"cross-ns-stripprefix": {
    @@ -5157,6 +5190,16 @@ func TestCrossNamespace(t *testing.T) {
     								Query:   "/{status}.html",
     							},
     						},
    +						"default-test-chain": {
    +							Chain: &dynamic.Chain{
    +								Middlewares: []string{"cross-ns-stripprefix"},
    +							},
    +						},
    +						"default-test-chain-cross-provider": {
    +							Chain: &dynamic.Chain{
    +								Middlewares: []string{"other-middleware@kubernetescrd"},
    +							},
    +						},
     					},
     					Services: map[string]*dynamic.Service{
     						"default-test-crossnamespace-route-6b204d94623b3df4370c": {
    @@ -5211,6 +5254,19 @@ func TestCrossNamespace(t *testing.T) {
     								PassHostHeader: pointer(true),
     							},
     						},
    +						"default-test-crossnamespace-route-4932ffbbcd99474df323": {
    +							LoadBalancer: &dynamic.ServersLoadBalancer{
    +								Servers: []dynamic.Server{
    +									{
    +										URL: "http://10.10.0.1:80",
    +									},
    +									{
    +										URL: "http://10.10.0.2:80",
    +									},
    +								},
    +								PassHostHeader: pointer(true),
    +							},
    +						},
     					},
     					ServersTransports: map[string]*dynamic.ServersTransport{},
     				},
    

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

7

News mentions

0

No linked articles in our index yet.