Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐹 Go
Not in CISA KEV

CVE-2026-88007 — traefik

Fix: traefik/traefik@ff39c47

CVE-2026-88007 is a Improper Authentication vulnerability in github.com/traefik/traefik/v3. A fix is available for github.com/traefik/traefik/v3 — see the affected versions and patch details below.

Traefik HTTP/3 Backend NTLM Connection Reuse

Also known asGHSA-qqjf-53cj-pwvvGO-2026-6466
Published
Updated
Affected
2 pkgs
Patched
2 / 2
Exploits
None indexed
Exploitation data as of Oct 11, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

No confirmed exploitation observed yet

  • CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
  • A successful exploit gives an attacker total control of the affected component, not partial access.
  • CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-88007.

EPSS Exploitation Probability

via FIRST.org ↗
0.6%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs47th percentile — riskier than 47% of all scored CVEsHighest risk
0.10%0.43%0.77%1.10%0.6%0.6%Oct 26Oct 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

Real-World Exposure

2 pkgs affected
🐹github.com/traefik/traefik/v3🐹github.com/traefik/traefik/v2

Real-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

Traefik's HTTP/3 request path did not initialize the connection-scoped backend transport holder that isolates connection-bound NTLM and Negotiate (Kerberos) authentication on the HTTP/1.1 and HTTP/2 paths. The HTTP/3 entrypoint reuses the HTTPS handler chain and reaches the same backend round-tripper, but its ConnContext never called service.AddTransportOnContext, so kerberosRoundTripper fell back to the shared backend transport instead of a per-frontend-connection pool. On a route served over HTTP/3 to a backend that binds identity to a persistent connection via NTLM or Negotiate, an unrelated HTTP/3 client could be assigned a backend connection already authenticated as a victim and inherit that identity, reading victim-only data and performing actions as the victim without presenting the victim's credentials. Affected deployments require HTTP/3 enabled on the entrypoint, a backend using connection-bound NTLM/Negotiate authentication, and backend keep-alive; deployments using ordinary per-request authentication are not affected.

Patches

For more information

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

<details> <summary>Original Description</summary>

Traefik HTTP/3 Backend NTLM Connection Reuse

Summary

Traefik's HTTP/3 request path does not initialize the connection-scoped backend transport state that Traefik uses to isolate connection-bound NTLM and Negotiate authentication for HTTP/1.1 and HTTP/2. When a backend keeps authenticated identity on a persistent HTTP/1.1 TCP connection, an unrelated HTTP/3 client can reuse a victim-authenticated backend connection and inherit that backend identity.

In the attached reproduction, the HTTPS/HTTP/1.1 control case behaves correctly and isolates the attacker, but the HTTP/3 case allows a second unauthenticated client to read victim-only data and execute a state-changing request as actor=victim.

Validated target:

  • Repository: traefik/traefik
  • Commit: f2d0794417e4d06343e6e7c4722143f5b34bee45
  • Validation time: 2026-08-25T06:48:02Z
  • Commit time: 2026-08-24T08:26:06Z
  • Patched status: not evaluated

Details

The issue is caused by a protocol-parity gap between the normal TCP HTTP entrypoint path and the HTTP/3 entrypoint path.

For HTTP/1.1 and HTTP/2, Traefik explicitly creates a connection-scoped holder that can later store a dedicated RoundTripper for NTLM or Negotiate:

// pkg/server/server_entrypoint_tcp.go:691-703
var connContext multipleConnContext
connContext.AddConnContextFunc(func(ctx context.Context, c net.Conn) context.Context {
	// This adds an empty struct in order to store a RoundTripper in the ConnContext in case of Kerberos or NTLM.
	ctx = service.AddTransportOnContext(ctx)

	if tlsConn, ok := c.(*tls.Conn); ok {
		if tlsConnWithOptionsName, ok := tlsConn.NetConn().(tcp.TLSConn); ok {
			return tcp.AddTLSOptionsNameInContext(ctx, tlsConnWithOptionsName.TLSOptionsName)
		}
	}

	return ctx
})

That helper installs the per-connection holder, and kerberosRoundTripper depends on it. If the holder is absent, it falls back to the shared original backend transport. If NTLM or Negotiate is detected, it stores a dedicated cloned RoundTripper into that holder so future requests stay on the authenticated backend connection:

// pkg/server/service/transport.go:374-402
func AddTransportOnContext(ctx context.Context) context.Context {
	return context.WithValue(ctx, transportKey, &stickyRoundTripper{})
}

type kerberosRoundTripper struct {
	new                  func() http.RoundTripper
	OriginalRoundTripper http.RoundTripper
}

func (k *kerberosRoundTripper) RoundTrip(request *http.Request) (*http.Response, error) {
	value, ok := request.Context().Value(transportKey).(*stickyRoundTripper)
	if !ok {
		return k.OriginalRoundTripper.RoundTrip(request)
	}

	if value.RoundTripper != nil {
		return value.RoundTripper.RoundTrip(request)
	}

	resp, err := k.OriginalRoundTripper.RoundTrip(request)

	// If we found that we are authenticating with Kerberos (Negotiate) or NTLM.
	// We put a dedicated roundTripper in the ConnContext.
	// This will stick the next calls to the same connection with the backend.
	if err == nil && containsNTLMorNegotiate(resp.Header.Values("WWW-Authenticate")) {
		value.RoundTripper = k.new()
	}
	return resp, err
}

For HTTP/3, the server reuses the normal HTTPS handler chain, but its ConnContext only propagates the TLS options name and does not call service.AddTransportOnContext:

// pkg/server/server_entrypoint_tcp_http3.go:65-80
h3.Server = &http3.Server{
	Addr:      config.GetAddress(),
	Port:      config.HTTP3.AdvertisedPort,
	Handler:   httpsServer.Server.(*http.Server).Handler,
	TLSConfig: &tls.Config{GetConfigForClient: h3.getTLSConfigForClient},
	QUICConfig: &quic.Config{
		Allow0RTT: false,
	},
	ConnContext: func(ctx context.Context, c *quic.Conn) context.Context {
		tlsOptionsName, err := h3.getTLSOptionsName(c)
		if err != nil {
			log.Error().Msgf("Error getting TLS options name for client: %v", err)
			return ctx
		}
		return tcp.AddTLSOptionsNameInContext(ctx, tlsOptionsName)
	},
}

This means HTTP/3 requests reach the same reverse-proxy and backend transport logic as HTTPS, but without the connection-scoped transport holder that NTLM and Negotiate isolation relies on.

In practice, the flow is:

  1. A victim authenticates through Traefik to a backend that binds identity to the backend TCP connection using NTLM or Negotiate.
  2. Because the HTTP/3 request context does not contain transportKey, kerberosRoundTripper uses the shared OriginalRoundTripper.
  3. No frontend-connection-specific dedicated backend pool is installed for that HTTP/3 client.
  4. A second unrelated HTTP/3 client can be assigned the same backend TCP connection after the victim has authenticated it.
  5. That second client inherits the victim's backend identity without sending the victim's credentials.

The attached verifier demonstrates both the negative control and the exploit path:

  • HTTPS/HTTP/1.1 control case: the attacker uses a separate frontend connection and correctly receives 401
  • HTTP/3 exploit case: the attacker uses a separate HTTP/3 client with no Authorization header, reads resource=secret actor=victim, executes action=transfer actor=victim to=attacker amount=5000, and hits the same backend TCP connection identifier as the victim

PoC

See the reproduction materials at: https://gist.github.com/OneZ3r0/41da8e8b79ebbe444a94f8a2a3a30895

The gist can also be downloaded as a ZIP archive.

Files included in this gist:

  • run.sh
  • Dockerfile
  • .dockerignore
  • go.mod
  • go.sum
  • verify.go

The package is intentionally kept as a single-container reproduction:

  1. run.sh builds a local image for the pinned target commit
  2. the Dockerfile builds both Traefik and the verifier during image build
  3. the container runs the verifier directly as its entrypoint
  4. the verifier starts a synthetic backend, launches Traefik, runs the HTTPS/HTTP/1.1 control case, then runs the HTTP/3 exploit case

Run:

./run.sh

run.sh defaults to the validated commit above. To override it explicitly:

PRODUCT_COMMIT=f2d0794417e4d06343e6e7c4722143f5b34bee45 ./run.sh

Expected terminal result:

REPRODUCED: HTTP/1.1 isolates the authenticated backend connection, but HTTP/3 reuses the victim-authenticated backend connection for a different client and executes an unauthorized state-changing request as the victim.

Important observed behavior from the PoC:

  • the HTTP/1.1 control case succeeds only if a fresh attacker connection receives 401
  • the HTTP/3 exploit case succeeds only if the attacker reads victim-only data without sending Authorization
  • the HTTP/3 exploit case succeeds only if the attacker performs /transfer?to=attacker&amount=5000 as actor=victim
  • the HTTP/3 exploit case succeeds only if the attacker uses the same backend TCP connection identifier as the victim

Environment notes:

  • Docker is required
  • the build fetches the target Traefik source from GitHub
  • no production credentials or external NTLM service are required; the verifier includes a synthetic NTLM-like backend specifically to demonstrate connection-bound identity reuse

Impact

This is a cross-client authorization bypass affecting deployments that expose HTTP/3 routes to backends using connection-bound NTLM or Negotiate authentication with persistent backend connection reuse.

In the verified reproduction, an unauthenticated second client can:

  • read victim-only data
  • perform a state-changing action as the victim
  • reuse a backend TCP connection that has already been authenticated as the victim

Attack prerequisites:

  • HTTP/3 enabled on the Traefik entrypoint
  • a routed backend using connection-bound NTLM or Negotiate authentication
  • backend keep-alive and backend connection reuse enabled
  • the attacker can reach the same route as the victim

Deployments using ordinary per-request authentication are not affected by this specific issue.

</details> ---

Affected Packages

2 total 2 fixed
EcosystemPackageVulnerable rangeFix
🐹Gogithub.com/traefik/traefik/v3≥ 3.0.0&&< 3.7.133.7.13go get github.com/traefik/traefik/v3@v3.7.13
🐹Gogithub.com/traefik/traefik/v2≥ 2.11.0&&< 2.11.572.11.57go get github.com/traefik/traefik/v2@v2.11.57

Affected Products

1 product · 2 configurations
Application
traefiktraefik
≥ 3.0.0 && < 3.7.12
range

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/traefik/traefik/v3, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update github.com/traefik/traefik/v3 to 3.7.13 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-88007 is resolved across your whole dependency graph.

  3. Workarounds

    Put an independent control in front of the weakness: restrict the affected endpoint or interface to trusted networks, require an additional authentication factor or proxy-level check, and invalidate existing sessions and credentials in case the flaw has already been used.

Fixing This On Your OS

If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.

Red HatCritical

A flaw in Traefik's HTTP/3 ConnContext allows unauthenticated remote attackers to bypass authentication on backends using connection-bound NTLM or Negotiate protocols. Traefik fails to invoke service.AddTransportOnContext for HTTP/3 entrypoints, causing kerberosRoundTripper to share a single backend transport across…

Workaround published by Red Hat
Disable HTTP/3 on Traefik entrypoints handling traffic for backends utilizing NTLM or Negotiate authentication, or disable HTTP/3 globally in the static configuration by removing or setting 'experimental.http3' / entrypoint HTTP/3 settings to false until updated packages are deployed.
Source: Red Hat security advisory for CVE-2026-88007 (CC BY 4.0)

Frequently Asked Questions

## Summary Traefik's HTTP/3 request path did not initialize the connection-scoped backend transport holder that isolates connection-bound NTLM and Negotiate (Kerberos) authentication on the HTTP/1.1 and HTTP/2 paths. The HTTP/3 entrypoint reuses the HTTPS handler chain and reaches the same backend round-tripper, but its `ConnContext` never called `service.AddTransportOnContext`, so `kerberosRoundTripper` fell back to the shared backend transport instead of a per-frontend-connection pool. On a route served over HTTP/3 to a backend that binds identity to a persistent connection via NTLM or Nego
O3 Security · Impact-Aware SCA

Is CVE-2026-88007 in your dependencies?

Find it across Go, including transitive dependencies.

CVE-2026-88007: traefik — Fixed in 3.7.13