This is a side door created by a routing shortcut, not a skeleton key for every Traefik box
CVE-2026-48020 affects Traefik when a public router uses PathPrefix together with the StripPrefix middleware, and a separate router protects sensitive paths like /admin or /internal/config with authentication. In vulnerable builds (<= v2.11.46, <= v3.6.17, <= v3.7.1), a request such as /api../admin or /api%2e%2e/admin can match the public route first, then be normalized after prefix stripping into a protected backend path. The result is route-level auth bypass, not a generic Traefik takeover.
The vendor/CNA tagged this High with CVSS v4 7.8, and the underlying bug is real. Operationally, though, that overstates fleet-wide urgency: exploitation requires a fairly specific routing pattern, internet reachability, and a backend path that becomes sensitive only after normalization. For a 10,000-host estate, this is a configuration-dependent edge-proxy bug with potentially serious local impact but a meaningfully narrower exposed population than a universal unauthenticated RCE.
4 steps from start to impact.
Find an exposed Traefik edge with the risky route design
PathPrefix and StripPrefix, while a separate route protects backend paths with auth. This is the real gate: the bug is not exploitable just because Traefik is present; the routing topology has to line up.- Traefik is reachable from the attacker's network position
- A public router uses
PathPrefix(...)withStripPrefix - A separate authenticated/protected route exists for backend paths
- Many deployments use host-based routing only and never use this pattern
- A lot of enterprise admin paths are not exposed through the same public entrypoint
- Internal-only Traefik deployments are already outside unauthenticated internet reach
Send a normalization payload
curl, the attacker sends a crafted path such as /api../admin or /api%2e%2e/admin. At routing time, the public PathPrefix route matches; after StripPrefix, path normalization changes the effective backend request into /admin or another protected path.- The public route prefix can be abused with
..or%2e%2esegments - Normalization occurs after prefix stripping in the vulnerable build
- Some upstream WAFs, CDNs, or path-normalization filters may reject obvious traversal-style payloads
- Custom route patterns like
PathRegexp(^/api(/|$))orPathPrefix(/api/)break the bypass
/../, /.., or percent-encoded dot segments near public prefixes. Default vuln scanners are unlikely to safely validate this without custom checks.Bypass the protected router boundary
- The protected resource is reachable on the same backend/service path after normalization
- Authentication lives at the route boundary rather than solely inside the backend app
- If the backend performs its own strong auth, the proxy bypass alone may not yield sensitive access
- If the protected endpoint is absent, the attack falls flat into 404s
Land impact on the backend, not on Traefik itself
/admin/exec endpoint, but that is conditional backend impact, not a built-in Traefik RCE.- Sensitive backend functionality exists behind the bypassed route
- The backend trusts Traefik to have already enforced auth
- Many backends add their own app-layer auth and reduce blast radius
- This does not inherently provide host compromise or container escape
The supporting signals.
| In-the-wild status | No CISA KEV listing found and no reliable public exploitation reporting found as of 2026-06-05. I found public advisory material and PoC detail, but not campaign evidence. |
|---|---|
| Public PoC status | Yes — the GitHub advisory itself includes a working PoC path set and expected vulnerable output using /api../admin and /api%2e%2e/admin, plus a lab scenario reaching a protected /admin/exec endpoint. |
| Researcher / reporter | GitHub lists reporter H4ck2 on the advisory page; the advisory body attributes the report to WonYun / kyun0. |
| EPSS | I did not find a public FIRST EPSS score for this CVE yet. Treat EPSS as unavailable / too new to rely on, not as evidence of low risk. |
| KEV status | Not KEV-listed. |
| CNA severity | GitHub Security Advisory / Traefik CNA published High 7.8 with 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. |
| Affected versions | <= v2.11.46, <= v3.6.17, and <= v3.7.1 according to the Traefik advisory. |
| Fixed versions | Upgrade to v2.11.48, v3.6.19, or v3.7.3. I did not find distro-specific backport guidance in the sources reviewed. |
| Exposure reality | Traefik is a common internet-facing reverse proxy. As context, Censys previously reported over 14,000 exposed Traefik dashboards in public scans; that is not a CVE-specific count, but it supports the view that exposed Traefik footprint is non-trivial. |
| Disclosure timeline | Advisory published 2026-06-05; fix PR #13215 merged 2026-05-28; release v3.7.3 published 2026-06-04 and explicitly lists CVE-2026-48020 as fixed. |
noisgate verdict.
The decisive downward pressure is configuration specificity: the bug is only exploitable when a public PathPrefix + StripPrefix route and a separate protected route create the exact normalization gap. This is still a real unauthenticated auth bypass on edge infrastructure, but it is not a broad all-Traefik compromise and the blast radius is bounded by what the backend exposes behind that route design.
Why this verdict
- Unauthenticated remote is real — attacker position is internet-facing and no credentials or user interaction are needed once the bad route design exists, so this is not hand-wavy lab-only theory.
- Config dependency cuts the reachable population — exploitation requires a public
PathPrefixroute,StripPrefix, a separate protected route, and backend-sensitive paths behind the same proxy. That compounding prerequisite stack pushes the score down from the vendor-style baseline. - Impact is boundary bypass, not platform takeover — the bug can expose admin/internal functionality and even enable downstream RCE *if* the backend already has an execution primitive, but Traefik itself is not handing out code execution or host compromise.
Why not higher?
This is not a universal pre-auth RCE, memory corruption bug, or auth bypass that fires on default installs. Real-world exploitability depends on an operator-created routing topology that many enterprises will simply not have, and some backends will still enforce their own auth after the proxy mistake.
Why not lower?
The attack is still unauthenticated, remote, and edge-facing where present, which always matters more than an internal-only footgun. If the vulnerable pattern exists in front of admin or internal APIs, the business impact can be immediate and ugly even without host-level compromise.
What to do — in priority order.
- Hunt for
StripPrefixon public routes — Search file-provider configs, Helm values, Kubernetes CRDs, Docker labels, and Compose manifests for public routers that combinePathPrefixandStripPrefix. For a MEDIUM verdict there is no mitigation SLA — go straight to the 365-day remediation window, but this hunt is fast and should be done early because it identifies the small subset that actually matters. - Tighten prefix boundaries — Where you cannot patch immediately, change public route matching from loose patterns to stricter ones the advisory verified in lab, such as
PathRegexp(^/api(/|$))orPathPrefix(/api/)withStripPrefix(/api/). There is no noisgate mitigation SLA for MEDIUM, so apply this opportunistically where config changes are easy while planning patching inside the remediation window. - Block traversal-style payloads upstream — Add WAF/CDN/ingress filtering for requests containing
..,%2e%2e, and similar encoded dot-segment tricks on public prefixes that feed Traefik. This is a solid temporary choke point, especially for internet-facing proxies, but it should be treated as a hardening measure rather than the primary fix. - Require backend-side auth for admin paths — Do not rely solely on Traefik route boundaries for truly sensitive endpoints. If admin or internal APIs also enforce application auth, the proxy bypass collapses into a noisy but non-fatal routing bug.
- Patch to fixed Traefik releases — Move affected instances to
v2.11.48,v3.6.19, orv3.7.3. For this MEDIUM assessment there is no mitigation SLA — go straight to the 365-day remediation window, but externally exposed edge proxies using the risky pattern should be prioritized well ahead of that outer deadline.
MFAon the protected Traefik router alone does not help if the request never traverses that router's auth middleware.Version-only vulnerability scansoverstate urgency because the bug is highly config-dependent; they find exposed code paths, not exploitable deployments.Assuming sanitizePath is enoughis unsafe here; the bug is specifically about path handling afterStripPrefix, so generic path sanitization settings are not the same as fixing this authorization boundary problem.
Crowdsourced verification payload.
Run this on the Traefik host, container node, or CI image-validation job. Invoke it as sudo bash verify-cve-2026-48020.sh /etc/traefik or point it at the directory where your Traefik YAML/TOML/labels live; root is helpful if you want it to inspect Docker metadata and protected config paths. The script returns VULNERABLE when it finds both a vulnerable Traefik version and risky config indicators, PATCHED when the version is fixed, and UNKNOWN when it cannot prove either state.
#!/usr/bin/env bash
# verify-cve-2026-48020.sh
# Detect likely exposure to CVE-2026-48020 (Traefik StripPrefix route-level auth bypass)
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN
set -u
CFG_DIR="${1:-/etc/traefik}"
VERSION=""
FOUND_SOURCE=""
RISKY_CONFIG=0
STRIPPREFIX_FOUND=0
PATHPREFIX_FOUND=0
AUTH_HINT_FOUND=0
verlte() {
[ "$1" = "$2" ] && return 0
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" = "$1" ]
}
vergte() {
[ "$1" = "$2" ] && return 0
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | tail -n1)" = "$1" ]
}
extract_semver() {
echo "$1" | grep -Eo 'v?[0-9]+\.[0-9]+\.[0-9]+' | head -n1
}
check_fixed() {
local v="$1"
if vergte "$v" "v3.7.3"; then return 0; fi
if vergte "$v" "v3.6.19" && verlte "$v" "v3.6.999"; then return 0; fi
if vergte "$v" "v2.11.48" && verlte "$v" "v2.11.999"; then return 0; fi
return 1
}
check_vuln_range() {
local v="$1"
if vergte "$v" "v3.7.0" && verlte "$v" "v3.7.1"; then return 0; fi
if vergte "$v" "v3.6.0" && verlte "$v" "v3.6.17"; then return 0; fi
if vergte "$v" "v2.11.0" && verlte "$v" "v2.11.46"; then return 0; fi
return 1
}
# 1) Try local traefik binary
if command -v traefik >/dev/null 2>&1; then
VERSION=$(traefik version 2>/dev/null | grep -Eo 'Version:\s*v?[0-9]+\.[0-9]+\.[0-9]+' | awk '{print $2}')
if [ -n "$VERSION" ]; then
FOUND_SOURCE="local traefik binary"
fi
fi
# 2) Try Docker image / running container if version still unknown
if [ -z "$VERSION" ] && command -v docker >/dev/null 2>&1; then
VERSION=$(docker ps --format '{{.Image}}' 2>/dev/null | grep -E '^traefik:v?[0-9]+\.[0-9]+\.[0-9]+' | head -n1 | sed 's/^traefik://')
if [ -n "$VERSION" ]; then
FOUND_SOURCE="running docker image"
fi
fi
# 3) Try podman
if [ -z "$VERSION" ] && command -v podman >/dev/null 2>&1; then
VERSION=$(podman ps --format '{{.Image}}' 2>/dev/null | grep -E '^traefik:v?[0-9]+\.[0-9]+\.[0-9]+' | head -n1 | sed 's/^traefik://')
if [ -n "$VERSION" ]; then
FOUND_SOURCE="running podman image"
fi
fi
# Normalize version prefix
if [ -n "$VERSION" ]; then
VERSION=$(extract_semver "$VERSION")
case "$VERSION" in
v*) ;;
*) VERSION="v$VERSION" ;;
esac
fi
# Config inspection
if [ -d "$CFG_DIR" ]; then
if grep -RIEq 'stripPrefix|stripprefix' "$CFG_DIR" 2>/dev/null; then
STRIPPREFIX_FOUND=1
fi
if grep -RIEq 'PathPrefix\(|pathprefix|PathRegexp\(' "$CFG_DIR" 2>/dev/null; then
PATHPREFIX_FOUND=1
fi
if grep -RIEq 'basicAuth|digestAuth|forwardAuth|jwt|oidc|oauth|ipAllowList|ipWhiteList|middlewares:.*auth|authentication' "$CFG_DIR" 2>/dev/null; then
AUTH_HINT_FOUND=1
fi
fi
if [ "$STRIPPREFIX_FOUND" -eq 1 ] && [ "$PATHPREFIX_FOUND" -eq 1 ]; then
RISKY_CONFIG=1
fi
# Decision logic
if [ -n "$VERSION" ] && check_fixed "$VERSION"; then
echo "PATCHED: Traefik version $VERSION ($FOUND_SOURCE) is at or above a fixed release for its branch."
exit 0
fi
if [ -n "$VERSION" ] && check_vuln_range "$VERSION"; then
if [ "$RISKY_CONFIG" -eq 1 ]; then
echo "VULNERABLE: Traefik version $VERSION is in an affected range and config under $CFG_DIR contains StripPrefix + PathPrefix indicators."
if [ "$AUTH_HINT_FOUND" -eq 1 ]; then
echo "NOTE: Auth-related middleware hints were also found; review for public-prefix to protected-path bypass patterns."
fi
exit 1
fi
echo "UNKNOWN: Traefik version $VERSION is in an affected range, but this script did not prove the risky routing pattern in $CFG_DIR."
exit 2
fi
if [ -z "$VERSION" ]; then
echo "UNKNOWN: Could not determine Traefik version from local binary or container runtime."
exit 2
fi
echo "UNKNOWN: Detected version $VERSION, but branch/fix status could not be classified by this script."
exit 2
If you remember one thing.
StripPrefix on public path-based routes in front of admin or internal backends. For this MEDIUM assessment there is no noisgate mitigation SLA — go straight to the 365-day remediation window, so your formal deadline is to complete patching inside the noisgate remediation SLA of <= 365 days; in practice, exposed edge proxies matching the risky pattern should be moved first, while the rest can be handled as normal platform maintenance rather than emergency change work.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.