{"id":"CVE-2026-54764","aliases":["GHSA-3q9r-p662-5j8m"],"title":"Traefik: ForwardAuth middleware leaks X-Forwarded-Port spoofing via untrusted X-Forwarded-Proto when trustForwardHeader=false","summary":"Traefik: ForwardAuth middleware leaks X-Forwarded-Port spoofing via untrusted X-Forwarded-Proto when trustForwardHeader=false","severity":"medium","cvss":5.8,"cwe":["CWE-345"],"vendor":"traefik","product":"github.com/traefik/traefik/v2","ecosystem":"go","affected":["github.com/traefik/traefik/v2 <= 2.11.50","github.com/traefik/traefik/v3 <= 3.6.21","github.com/traefik/traefik/v3 >= 3.7.0, <= 3.7.5","github.com/traefik/traefik <= 1.7.34"],"patched":["github.com/traefik/traefik/v2 2.11.51","github.com/traefik/traefik/v3 3.6.22","github.com/traefik/traefik/v3 3.7.6"],"published":"2026-08-06","updated":"2026-08-06","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-3q9r-p662-5j8m","references":[{"url":"https://github.com/traefik/traefik/security/advisories/GHSA-3q9r-p662-5j8m"},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-54764"},{"url":"https://github.com/traefik/traefik/pull/13344"},{"url":"https://github.com/traefik/traefik/commit/7ae92d8c2c10ac04ef5a03df0ed5019ce0f44b2d"},{"url":"https://github.com/traefik/traefik/releases/tag/v2.11.51"},{"url":"https://github.com/traefik/traefik/releases/tag/v3.6.22"},{"url":"https://github.com/traefik/traefik/releases/tag/v3.7.6"},{"url":"https://github.com/advisories/GHSA-3q9r-p662-5j8m"}],"tags":["ghsa","go"],"epss":0.00281,"epssPercentile":0.18248,"ingestedAt":"2026-08-06T17:00:12.806Z","slug":"CVE-2026-54764","body":"## Overview\n\n## Summary\n\nThere 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.\n\n## Patches\n\n- https://github.com/traefik/traefik/releases/tag/v2.11.51\n- https://github.com/traefik/traefik/releases/tag/v3.6.22\n- https://github.com/traefik/traefik/releases/tag/v3.7.6\n\n## For more information\n\nIf you have any questions or comments about this advisory, please [open an issue](https://github.com/traefik/traefik/issues).\n\n<details>\n<summary>Original Description</summary>\n\n### Summary\n\n  The ForwardAuth middleware, even when configured with `trustForwardHeader: false`,\n  still derives the `X-Forwarded-Port` header sent to the authentication service by\n  reading the **attacker-controlled** `X-Forwarded-Proto` header from the original\n  incoming request. This allows an unauthenticated remote attacker to cause Traefik\n  to forward `X-Forwarded-Port: 443` to the auth service on a plain HTTP connection,\n  creating an inconsistency that can bypass port-based authorization checks.\n\n  ### Details\n\n  The fix introduced in commit `5e1de2258` (released as part of the April 2026 security\n  advisory GHSA-6384-m2mw-rf54) correctly strips all X-Forwarded-* headers from the\n  forwarded auth request when `trustForwardHeader=false`, and reconstructs\n  `X-Forwarded-Proto` from the actual TLS state of the connection (`req.TLS`).\n\n  However, the reconstruction of `X-Forwarded-Port` is delegated to the helper\n  `forwardedPort(req)` which receives the **original request** (`req`) rather than\n  the sanitized forward request (`forwardReq`):\n\n  ```go\n  // pkg/middlewares/auth/forward.go – writeHeader()\n  if !trustForwardHeader {\n      forwardedheaders.DeleteXForwardedHeaders(forwardReq.Header) // strips all X-Fwd-* from forwardReq\n  }\n  // ...\n  if _, ok := forwardReq.Header[forwardedheaders.XForwardedPort]; !ok {\n      forwardReq.Header.Set(forwardedheaders.XForwardedPort, forwardedPort(req)) // ← req = ORIGINAL\n  }\n\n  // pkg/middlewares/auth/forward.go – forwardedPort()\n  func forwardedPort(req *http.Request) string {\n      if _, port, err := net.SplitHostPort(req.Host); err == nil && port != \"\" {\n          return port\n      }\n      // Reads attacker-controlled header on the ORIGINAL request:\n      if req.Header.Get(forwardedheaders.XForwardedProto) == \"https\" || ... {\n          return \"443\"\n      }\n      if req.TLS != nil {\n          return \"443\"\n      }\n      return \"80\"\n  }\n\n  Result when trustForwardHeader=false and attacker sends X-Forwarded-Proto: https\n  on a plain HTTP connection:\n\n  ┌──────────────────────────────────┬──────────┬────────┐\n  │ Header forwarded to auth service │ Expected │ Actual │\n  ├──────────────────────────────────┼──────────┼────────┤\n  │ X-Forwarded-Proto                │ http     │ http ✓ │\n  ├──────────────────────────────────┼──────────┼────────┤\n  │ X-Forwarded-Port                 │ 80       │ 443 ✗  │\n  └──────────────────────────────────┴──────────┴────────┘\n```\n  The inconsistency between Proto=http and Port=443 is exploitable against any\n  authentication service that gates access based on X-Forwarded-Port.\n\n  ### PoC\n\n  Traefik configuration:\n\n  ```http:\n    middlewares:\n      my-auth:\n        forwardAuth:\n          address: \"http://auth-service/\"\n          trustForwardHeader: false  # security setting, but still bypassable\n    routers:\n      api:\n        rule: \"PathPrefix(`/api`)\"\n        middlewares:\n          - my-auth\n        service: backend\n\n  Auth service logic (example victim):\n  # auth-service checks: only port 443 requests are considered \"secure\"\n  port = request.headers.get(\"X-Forwarded-Port\", \"80\")\n  proto = request.headers.get(\"X-Forwarded-Proto\", \"http\")\n  if port == \"443\":\n      return 200  # grant access\n  return 403\n```\n  Attack:\n\n  Plain HTTP connection, no TLS – but spoofs port 443\n  curl -H \"X-Forwarded-Proto: https\" http://traefik.example.com/api/admin\n  Auth service receives X-Forwarded-Port: 443 → grants access\n\n  Verification: Enable Traefik debug logging and observe X-Forwarded-Port: 443\n  in the auth request while the connection is plain HTTP.\n\n ### Impact\n\n  Any deployment using the ForwardAuth middleware with trustForwardHeader: false where\n  the downstream authentication service uses X-Forwarded-Port to make authorization\n  decisions is vulnerable to privilege escalation. An unauthenticated attacker can\n  bypass port-based security checks (e.g., \"only allow requests arriving on HTTPS port\n  443\") by injecting a single X-Forwarded-Proto: https header on a plain HTTP\n  connection.\n\n  This is a regression of the incomplete fix for GHSA-6384-m2mw-rf54: while the\n  X-Forwarded-Prefix and X-Forwarded-Proto spoofing vectors were addressed, the\n  X-Forwarded-Port vector was missed.\n\n</details>\n\n---\n\n## Affected packages\n\n- `github.com/traefik/traefik/v2 <= 2.11.50`\n- `github.com/traefik/traefik/v3 <= 3.6.21`\n- `github.com/traefik/traefik/v3 >= 3.7.0, <= 3.7.5`\n- `github.com/traefik/traefik <= 1.7.34`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `github.com/traefik/traefik/v2 2.11.51`\n- `github.com/traefik/traefik/v3 3.6.22`\n- `github.com/traefik/traefik/v3 3.7.6`","depth":"sunlit","depthScore":32,"depthScoreParts":{"impact":31.9,"likelihood":0.1,"exploitation":0,"ransomware":0},"changes":[]}