Skip to main content
← All articles
self-hosting

Your reverse proxy is a patch treadmill: five Traefik releases in ten weeks

Your reverse proxy is a patch treadmill: five Traefik releases in ten weeks

I pin my Traefik image to an explicit tag, the way Coolify's own docs tell you to. The downside of a pinned tag is that nobody bumps it for you — and this quarter that turned into a chore. Five security-bearing patch releases in ten weeks. I went and read every advisory so you don't have to, and the reassuring part is that most of them need a setup you probably don't run. The useful part is the pattern they all share.

The treadmill

From Traefik's GitHub releases:

ReleaseDateAdvisories
3.7.1031 Jul3
3.7.1119 Aug4
3.7.1226 Aug3
3.7.134 Sep6
3.7.146 Oct8

And a support cliff while you're at it: Traefik 3.6 security support ended 16 Aug 2026, and the 2.11 line ended 7 Sep 2026. Anything 3.0–3.6 gets no more fixes; the destination is 3.7.x.

The ones worth understanding

Four, picked because they teach the pattern rather than because they'll all hit you:

  • GHSA-qqjf-53cj-pwvv / CVE-2026-88007, Critical 9.1. HTTP/3 clients can be routed onto a backend connection already authenticated via NTLM or Negotiate — inheriting another user's identity. Needs HTTP/3 enabled, a backend using connection-bound NTLM/Kerberos, and keep-alive. Ordinary per-request auth is safe. Fixed 3.7.13 / 2.11.57, no workaround.
  • GHSA-f52w-8j3h-j724 / CVE-2026-88009, High 8.8. A rootless/opaque HTTP/1 request-target like GET http:http://internal-vhost/admin HTTP/1.1 gets routed as / but forwarded verbatim. So path-scoped middleware is skipped, forwardAuth fails open (the auth server saw an opaque string, not /admin, and returned ALLOW), and your access log records /. Reassuringly, of seven backends tested, five rejected the form with a 400 — but you don't control which backend an attacker aims at.
  • GHSA-6jwx-7vp4-9847 / CVE-2026-40912, High 7.8. StripPrefixRegex desyncs the decoded path from the raw path, producing things like /./admin/.... Chain it with ForwardAuth/BasicAuth/DigestAuth and the auth layer misses the protected path while the backend normalizes it and serves it. No workaround.
  • Header aliasing (3.7.12). Go only canonicalizes header names on dashes, but CGI, WSGI, PHP and nginx all fold X-Auth-User, X_Auth_User and X.Auth.User into the same HTTP_X_AUTH_USER. A client sends an alias to smuggle past a header Traefik thought it managed. The fix is a new entry-point option aliasHeadersStrategy — and here's the trap: it defaults to keep, so upgrading alone fixes nothing. You set it to delete or reject, which then strip/reject any header with characters outside letters, digits and dashes — so a legit X_Request_Id-style header breaks too. Traefik logs a startup warning per entry point that hasn't chosen.

3.7.13 also quietly fixed h2c upgrade tunneling that bypasses the middleware chain, a header-sanitization bypass via request trailers, and a BasicAuth username-enumeration timing leak.

The pattern, and why it's a Drupal lesson

Read those four back to back and it's the same bug every time: the proxy and the backend parse the same request differently. The proxy decides /admin is really /, or that a header doesn't exist, and the backend disagrees — and the auth you bolted onto the proxy lives in exactly that gap.

Every one of these is an argument against enforcing access at the proxy. ForwardAuth deny-rules on /admin are the fragile layer. Drupal enforces permission in the app, on the resolved route, where there's no second parser to disagree — and that's precisely why none of these CVEs can route around Drupal's own access checks.

So the defensive takeaway isn't "patch and panic." It's: keep real authorization in the application, and treat proxy-level path rules as convenience, not security.

The honest ops cost

This is the part nobody puts in the release notes. Five releases in ten weeks. A tag you pin and must bump by hand. A fix (aliasHeadersStrategy) that's inert until you make a breaking-ish choice. If you run Coolify, the proxy is Traefik and the docs use traefik:v3.7.14 as the example tag — but I couldn't confirm which tag your Coolify version defaults to, and the config constants file carries none, so go look: Servers → Proxy → Configuration, and read the image: line yourself. Don't take a version number from a blog, including this one. And don't hand-edit the proxy compose on disk — Coolify will overwrite it.

Links

BM
Blue Moose
The moose behind Blue Moose. Full-stack PHP developer — Drupal by day, Symfony by night, tests always.