Pre-auth SSRF in self-hosted Next.js WebSocket upgrade handler — reach cloud metadata, internal services, any localhost port.
router-server.ts in the built-in Node.js server proxies upgrade requests with absolute URLs without validating that the routing layer explicitly authorized the target as a safe external rewritec4f69086 adds finished+statusCode guard before calling proxyRequest()The WebSocket upgrade handler in next.js's built-in Node.js server accepts absolute-form HTTP request URIs (e.g. GET http://169.254.169.254/latest/meta-data/) in the upgrade request and forwards them to proxyRequest() without validating that the routing layer explicitly authorized the target as a safe external rewrite.
An unauthenticated attacker sends a crafted HTTP Upgrade header with Connection: Upgrade and an absolute-form URI pointing to a cloud metadata endpoint or internal service — the server acts as a blind proxy.
Real-world impact: on a self-hosted next.js instance running inside a container/pod on AWS/GCP/Azure, a single WebSocket upgrade request to http://169.254.169.254/latest/meta-data/ exfiltrates IAM credentials (AccessKeyId, SecretAccessKey, Token). The same primitive reaches any port on localhost: Redis (:6379), PostgreSQL (:5432), internal admin panels, Kubernetes API.
AWS IMDSv1 is vulnerable. IMDSv2 (HttpTokens=required) is not, since it requires a PUT to mint the token first.
The fix adds two guards: finished must be true (routing explicitly marked target as a safe external rewrite) AND statusCode must be absent (no redirect/error returned). Only then does it call proxyRequest(). An absolute-form URI that wasn't explicitly rewritten by the routing layer now fails the finished check.
c4f69086parsedUrl.protocol before calling proxyRequest() — it never validated whether the routing layer had explicitly marked the target as a safe external rewrite. An absolute-form HTTP request URI (e.g. GET http://169.254.169.254/) causes Url.parse() to set parsedUrl.protocol to "http:", triggering the proxy path without any routing-layer authorization. The same bug class (absolute URI SSRF in proxy handling) is a recurring pattern in Node.js frameworks — see CVE-2024-29415 (ip package), CVE-2023-44487 (HTTP/2 Rapid Reset), and CVE-2024-21538 (axios SSRF).
router-server.ts is deep in next.js's built-in server code, not in application code. Reviewers trust the framework's internal handling more than their own code.resolveRoutes) suggests safety.GET http://169.254.169.254/...) looks like a normal HTTP request at first glance.
parsedUrl.protocolis set from the request-line URI — an attacker-controlled field. CallingproxyRequest(req, socket, parsedUrl, head)without afinished+statusCoderouting guard lets any absolute-form URI be proxied server-side. A request likeGET http://169.254.169.254/latest/meta-data/withUpgrade: websocketheaders reaches AWS/GCP metadata and returns IAM credentials. This is CWE-918 (SSRF), pre-auth, low complexity. IMDSv1 on AWS is exploitable; IMDSv2 (PUT-required token mint) is not. Internal services onlocalhost:6379,:5432,:8080are all reachable. Public PoC: github.com/dinosn/CVE-2026-44578.```suggestion // Fix: apply the same routing guards as normal HTTP proxy requests const { finished, matchedOutput, parsedUrl, statusCode } = await resolveRoutes({ req, res, isUpgradeReq: true, signal: signalFromNodeResponse(socket), }) if (matchedOutput) return socket.end() // Only proxy when routing explicitly marked the target as a safe external rewrite if (finished && parsedUrl.protocol) { if (!statusCode) { return await proxyRequest(req, socket, parsedUrl, head) } return socket.end() } // Upgrade request to non-rewrite target — reject cleanly ``` Fix: Upgrade to next.js 15.5.16+ / 16.2.5+. If you cannot upgrade immediately, block WebSocket upgrade headers (Connection: Upgrade,Upgrade: websocket) at your reverse proxy or load balancer if WebSockets are not required by your application. Enforce IMDSv2 on cloud VMs (aws ec2 modify-instance-metadata-options --http-tokens required) to prevent metadata credential exfiltration even if the SSRF is exploited.