4.5 KiB
Traefik — CWE-407 Disclosure Brief
2026-03-27 · Patch available — awaiting upstream merge
Finding
Three O(n²) defects in Traefik's middleware, observability, and config-loading subsystems. All three use slices.Contains over slices in hot paths — two fire on every request, one fires on every router during config loading. All patched. Speedup: 20× across all three.
The Defects
traefik-0001 (PATCHED — HIGH): pkg/middlewares/forwardedheaders/forwarded_header.go:229
// Per request — for each incoming header:
if slices.Contains(xHeaders, headerName) {
// O(H) scan per header per request
}
slices.Contains(xHeaders, headerName) called per incoming header on every request through the forwarded-headers middleware. For H trusted header names and K headers per request: O(K × H) per request. Fix: map[string]struct{} pre-built at middleware init. Measured ratio: 20×.
traefik-0002 (PATCHED — HIGH): pkg/observability/tracing/tracing.go:230
// Per request — for each URL query parameter:
if slices.Contains(safeQueryParams, paramName) {
// O(Q×P) scan per request for URL redaction
}
slices.Contains(safeQueryParams, paramName) called for every URL query parameter on every traced request. For P safe-param names and Q query parameters per request: O(Q × P) per request. Fix: map[string]struct{} pre-built at tracer init. Measured ratio: 20×.
traefik-0003 (PATCHED — MEDIUM): pkg/config/runtime/runtime_http.go:30
// During config loading — for each router:
for _, router := range routers {
for _, ep := range router.EntryPoints {
if slices.Contains(entryPoints, ep) {
// O(R×E) total across all routers
}
}
}
slices.Contains(entryPoints, ep) inside a per-router, per-entry-point loop during config loading. For R routers and E entry points: O(R × E) total. Fix: pre-build map[string]bool from entryPoints before the router loop. Measured ratio: 20×.
Complexity Proof
traefik-0001: Let H = len(xHeaders), K = headers per request, R = requests/second.
- Defective: O(K × H) per request → O(R × K × H) per second.
- Fixed: O(K) per request (map lookup) → O(R × K) per second.
- At H=20: 20× measured ratio.
traefik-0002: Let P = len(safeQueryParams), Q = query params per request URL, R = requests/second.
- Defective: O(Q × P) per request.
- Fixed: O(Q) per request via map lookup.
- At P=20: 20× measured ratio.
traefik-0003: Let R = number of routers, E = number of entry points, C = entry points per router.
- Defective: O(R × C × E) comparisons total during config load.
- Fixed: O(E) map build + O(R × C) lookups = O(R × C + E) total.
- At E=20 entry points: 20× reduction in entry-point comparisons.
Impact
traefik-0001 and traefik-0002 fire on every request passing through Traefik — the dominant cloud-native reverse proxy and ingress controller in Kubernetes environments. Traefik is deployed as the primary ingress for thousands of production Kubernetes clusters. traefik-0001 fires for every request using the forwarded-headers middleware (enabled by default in many configurations); traefik-0002 fires for every request with tracing enabled. traefik-0003 fires on every configuration reload, which in dynamic Kubernetes environments occurs frequently as services are deployed and scaled.
The Fix
All three fixes follow the same pattern: replace slices.Contains over a slice with a map[string]struct{} pre-built once at init/config-load time.
// Before (traefik-0001 representative)
if slices.Contains(xHeaders, headerName) { ... } // O(H) per header per request
// After
// CWE-407 fix: map[string]struct{} for O(1) lookup instead of O(H) slices.Contains scan.
xHeaderSet := make(map[string]struct{}, len(xHeaders))
for _, h := range xHeaders {
xHeaderSet[strings.ToLower(h)] = struct{}{}
}
// Per request:
if _, ok := xHeaderSet[headerName]; ok { ... } // O(1)
Same pattern applied at tracing.go:230 (safeQueryParams) and runtime_http.go:30 (entryPoints).
Patch
defects/traefik/patch/traefik-0001-0002-0003-slices-map.patch
What We Ask
- Confirm receipt and assign a GitHub Security Advisory or issue reference.
- Validate the patch against forwarded-headers, tracing, and config-loading test suites.
- Assess CVE eligibility — traefik-0001 and traefik-0002 fire on every request in production.
- Coordinate a disclosure date — we are targeting 90 days from first contact.
Contact: see cover email. This brief is confidential until coordinated disclosure.