# Traefik: Pre-authentication decision bypass due to forwarded alias spoofing

Traefik sanitizes only canonical X-Forwarded-* headers, so underscore aliases like X_Forwarded_Proto reach ForwardAuth backends and spoof trust context to bypass auth.

- Payout: Research
- Severity: high
- Program: Traefik
- Found by: fancymalware
- Disclosed: 2026-04-24
- CVE: CVE-2026-39858
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-5m6w-wvh7-57vm
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-5m6w-wvh7-57vm
- Tags: area:cloud domain:infra impact:internal-access kind:research platform:ghsa sev:high tech:go technique:parser-differential vuln:access-control vuln:auth-bypass vuln:host-header

**Target:** ForwardAuth / snippet auth middleware and forwarded-header sanitization
**Root cause:** Ingress sanitization only strips canonical X-Forwarded-* names, while ForwardAuth copies nearly all client headers into the auth subrequest without normalizing underscore alias forms; backends that normalize underscore/dash equivalently then trust attacker-supplied values.
**Steps:**
1. Configure a protected route using ForwardAuth or snippet-based auth with a backend that normalizes underscore and dash header names.
2. Send control request `GET / HTTP/1.1` with `Host: target.local` — expected denied.
3. Send `GET /protected HTTP/1.1` with `Host: app.example.local`, `X_Forwarded_Proto: https`, `X_Forwarded_Host: trusted.example` — expected allowed.
**How found:** Code review of the fixed canonical header list in forwarded_header.go against the wholesale header copy in forward.go/snippet.go revealed a trust boundary mismatch: alias header forms are neither normalized nor stripped.
**Exploitation:** Attacker sends a single crafted request carrying underscore alias headers (X_Forwarded_Proto: https, X_Forwarded_Host: trusted.example); Traefik forwards them intact to the auth backend, which normalizes them to canonical form and satisfies trust predicates, granting access to protected backends without credentials.
**Insight:** When a proxy sanitizes a fixed list of canonical header names, check whether the downstream auth service normalizes underscore/dash variants — the alias becomes an unsanitized shadow of the trusted header.

## Proof of concept (copied exactly from the original report)

**Exploit request with underscore alias forwarded headers**

```
GET /protected HTTP/1.1
Host: app.example.local
X_Forwarded_Proto: https
X_Forwarded_Host: trusted.example
Connection: close
```

