GHSA-3q9r-p662-5j8m
MEDIUMGHSA-3q9r-p662-5j8m is a medium-severity (CVSS 5.8) CWE-345 vulnerability in github.com/traefik/traefik/v2. O3 Security confirms whether GHSA-3q9r-p662-5j8m is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.
Traefik: ForwardAuth middleware leaks X-Forwarded-Port spoofing via untrusted X-Forwarded-Proto when trustForwardHeader=false
Blast Radius
github.com/traefik/traefik/v2🐹github.com/traefik/traefik/v3🐹github.com/traefik/traefik/v3🐹github.com/traefik/traefikReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.
Description
Summary
There is a medium severity vulnerability in Traefik's ForwardAuth middleware. Even when configured with trustForwardHeader: false, Traefik derives the X-Forwarded-Port header sent to the authentication service from the original incoming request instead of the sanitized forwarded request. As a result, an unauthenticated remote attacker can inject an X-Forwarded-Proto: https header over a plain HTTP connection and cause Traefik to forward X-Forwarded-Port: 443 to the auth service, bypassing port-based authorization checks. This is a regression of the incomplete fix for GHSA-6384-m2mw-rf54, which addressed the X-Forwarded-Proto and X-Forwarded-Prefix spoofing vectors but missed the X-Forwarded-Port vector.
Patches
- https://github.com/traefik/traefik/releases/tag/v2.11.51
- https://github.com/traefik/traefik/releases/tag/v3.6.22
- https://github.com/traefik/traefik/releases/tag/v3.7.6
For more information
If you have any questions or comments about this advisory, please open an issue.
<details> <summary>Original Description</summary>Summary
The ForwardAuth middleware, even when configured with trustForwardHeader: false,
still derives the X-Forwarded-Port header sent to the authentication service by
reading the attacker-controlled X-Forwarded-Proto header from the original
incoming request. This allows an unauthenticated remote attacker to cause Traefik
to forward X-Forwarded-Port: 443 to the auth service on a plain HTTP connection,
creating an inconsistency that can bypass port-based authorization checks.
Details
The fix introduced in commit 5e1de2258 (released as part of the April 2026 security
advisory GHSA-6384-m2mw-rf54) correctly strips all X-Forwarded-* headers from the
forwarded auth request when trustForwardHeader=false, and reconstructs
X-Forwarded-Proto from the actual TLS state of the connection (req.TLS).
However, the reconstruction of X-Forwarded-Port is delegated to the helper
forwardedPort(req) which receives the original request (req) rather than
the sanitized forward request (forwardReq):
// pkg/middlewares/auth/forward.go – writeHeader()
if !trustForwardHeader {
forwardedheaders.DeleteXForwardedHeaders(forwardReq.Header) // strips all X-Fwd-* from forwardReq
}
// ...
if _, ok := forwardReq.Header[forwardedheaders.XForwardedPort]; !ok {
forwardReq.Header.Set(forwardedheaders.XForwardedPort, forwardedPort(req)) // ← req = ORIGINAL
}
// pkg/middlewares/auth/forward.go – forwardedPort()
func forwardedPort(req *http.Request) string {
if _, port, err := net.SplitHostPort(req.Host); err == nil && port != "" {
return port
}
// Reads attacker-controlled header on the ORIGINAL request:
if req.Header.Get(forwardedheaders.XForwardedProto) == "https" || ... {
return "443"
}
if req.TLS != nil {
return "443"
}
return "80"
}
Result when trustForwardHeader=false and attacker sends X-Forwarded-Proto: https
on a plain HTTP connection:
┌──────────────────────────────────┬──────────┬────────┐
│ Header forwarded to auth service │ Expected │ Actual │
├──────────────────────────────────┼──────────┼────────┤
│ X-Forwarded-Proto │ http │ http ✓ │
├──────────────────────────────────┼──────────┼────────┤
│ X-Forwarded-Port │ 80 │ 443 ✗ │
└──────────────────────────────────┴──────────┴────────┘
The inconsistency between Proto=http and Port=443 is exploitable against any authentication service that gates access based on X-Forwarded-Port.
PoC
Traefik configuration:
middlewares:
my-auth:
forwardAuth:
address: "http://auth-service/"
trustForwardHeader: false # security setting, but still bypassable
routers:
api:
rule: "PathPrefix(`/api`)"
middlewares:
- my-auth
service: backend
Auth service logic (example victim):
# auth-service checks: only port 443 requests are considered "secure"
port = request.headers.get("X-Forwarded-Port", "80")
proto = request.headers.get("X-Forwarded-Proto", "http")
if port == "443":
return 200 # grant access
return 403
Attack:
Plain HTTP connection, no TLS – but spoofs port 443 curl -H "X-Forwarded-Proto: https" http://traefik.example.com/api/admin Auth service receives X-Forwarded-Port: 443 → grants access
Verification: Enable Traefik debug logging and observe X-Forwarded-Port: 443 in the auth request while the connection is plain HTTP.
Impact
Any deployment using the ForwardAuth middleware with trustForwardHeader: false where the downstream authentication service uses X-Forwarded-Port to make authorization decisions is vulnerable to privilege escalation. An unauthenticated attacker can bypass port-based security checks (e.g., "only allow requests arriving on HTTPS port 443") by injecting a single X-Forwarded-Proto: https header on a plain HTTP connection.
This is a regression of the incomplete fix for GHSA-6384-m2mw-rf54: while the X-Forwarded-Prefix and X-Forwarded-Proto spoofing vectors were addressed, the X-Forwarded-Port vector was missed.
</details>Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐹Go | github.com/traefik/traefik/v2 | all versions | 2.11.51 |
| 🐹Go | github.com/traefik/traefik/v3 | all versions | 3.6.22 |
| 🐹Go | github.com/traefik/traefik/v3 | ≥ 3.7.0&&< 3.7.6 | 3.7.6 |
| 🐹Go | github.com/traefik/traefik | all versions | No fix |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/traefik/traefik/v2. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.
Fix
Update github.com/traefik/traefik/v2 to 2.11.51 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-3q9r-p662-5j8m is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 pinpoints whether GHSA-3q9r-p662-5j8m is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.
Tailored to GHSA-3q9r-p662-5j8m. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is GHSA-3q9r-p662-5j8m in your dependencies?
O3 detects GHSA-3q9r-p662-5j8m across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.