← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
CVE-2026-44578 · CWE-918 · Disclosed 2026-05-13

Next

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is a valet key that only matters if you left the server-room side door unlocked

CVE-2026-44578 is a server-side request forgery bug in Next.js WebSocket upgrade handling. Affected versions are >=13.4.13 <15.5.16 and >=16.0.0 <16.2.5, and the exposure is specifically self-hosted deployments using the built-in Node.js server. The vulnerable path lets a crafted WebSocket upgrade request trick the origin into proxying to attacker-chosen internal or external destinations, including localhost services or cloud metadata endpoints.

The vendor's HIGH 8.6 is directionally fair, but a little hot for enterprise prioritization because the reachable population is narrower than the CVSS suggests. This is not a generic Next.js internet bug, not a Vercel-hosted issue, and not direct code execution; it is a deployment-contingent SSRF whose real damage depends on what the origin can reach over the network.

"Unauthenticated SSRF into your app tier is serious, but only for self-hosted Next.js origins using the built-in Node server"
02 · The Attack Path

4 steps from start to impact.

STEP 01

Reach a vulnerable origin

The attacker needs network reachability to a self-hosted Next.js application running the built-in Node.js server. In practice this usually means the app origin is directly internet-reachable or a reverse proxy forwards upgrade traffic to it. Weaponized tooling is trivial here: raw curl, nc, custom Python sockets, or a Nuclei template are enough.
Conditions required:
  • Internet or otherwise untrusted-network reachability to the Next.js origin
  • Application is self-hosted rather than Vercel-hosted
  • Deployment uses the built-in Node.js server
Where this breaks in practice:
  • A large chunk of enterprise Next.js traffic is terminated behind CDN/reverse-proxy layers
  • Some shops do not expose origins directly to the internet
  • Vercel-hosted deployments are explicitly not affected
Detection/coverage: Asset scanners can identify the product/version, but confirming exploitability requires deployment context. ProjectDiscovery added a Nuclei template for this CVE.
STEP 02

Send a crafted absolute-URL WebSocket upgrade

The exploit uses a crafted HTTP request with Connection: Upgrade and Upgrade: websocket, pointing the request line at an absolute URL. The public patch commit and tests show the vulnerable flow in router-server.ts; public PoC collections exist, so attackers do not need to rediscover the bug.
Conditions required:
  • Origin accepts or forwards WebSocket upgrade requests
  • Target version is in the vulnerable range
Where this breaks in practice:
  • Some reverse proxies normalize or restrict upgrade behavior
  • Applications that do not rely on upgrade handling may already block it upstream
Detection/coverage: WAF coverage is unreliable; Vercel's own May 7, 2026 security release says these advisories cannot be reliably blocked at the WAF layer.
STEP 03

Abuse the proxy path for SSRF

Once the upgrade request enters the vulnerable path, the origin can proxy to attacker-selected destinations. Public analysis and the vendor advisory call out internal services, administrative interfaces, and cloud metadata endpoints as the meaningful targets. Tooling at this stage is usually a custom socket client or PoC script tuned to observe reflected content or timing.
Conditions required:
  • The origin can egress to the chosen target
  • Internal target is routable from the app host/container
Where this breaks in practice:
  • Good egress controls can block metadata IPs and RFC1918 targets
  • Cloud metadata hardening such as AWS IMDSv2 reduces the easy-win path
  • Many internal services still require auth even if reached
Detection/coverage: Network telemetry is your friend: look for origin-side connections to 169.254.169.254, localhost admin ports, RFC1918 ranges, or unusual outbound destinations immediately after upgrade requests.
STEP 04

Turn SSRF into data access or cloud pivot

Impact is confidentiality-first: steal metadata tokens, enumerate internal APIs, or access admin endpoints unintentionally trusted from localhost or the app tier. This is why the CVSS is high even without direct integrity or availability impact. Real-world blast radius is determined by network adjacency and service trust, not by Next.js alone.
Conditions required:
  • Useful internal targets exist behind the app tier
  • Those targets expose sensitive data or issue credentials/tokens
Where this breaks in practice:
  • No direct RCE primitive in the vulnerable component
  • Well-segmented networks and hardened metadata services sharply reduce payoff
  • Blast radius is usually bounded to what that app host can already reach
Detection/coverage: EDR will not reliably catch the bug itself; detections should focus on unusual outbound connections from the Node.js process and suspicious metadata-access patterns.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusAs of 2026-06-01, I found no CISA KEV listing and no primary-source confirmation of active exploitation. Treat public PoC availability as a warning, not as proof of campaigns.
Proof-of-concept availabilityYes, public PoC exists. The vendor patch commit includes regression tests showing the exploit condition, third-party PoC writeups reference working exploit code, and ProjectDiscovery shipped a Nuclei template covering CVE-2026-44578.
EPSSUser-supplied intel says EPSS 0.0581. I did not verify the percentile directly from FIRST during this assessment, so treat percentile as unverified.
KEV statusNot listed in the CISA Known Exploited Vulnerabilities Catalog as checked for this assessment on 2026-06-01.
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N = unauthenticated remote reachability with high confidentiality impact, but no built-in integrity or availability primitive.
Affected versionsVendor advisory: >=13.4.13 <15.5.16 and >=16.0.0 <16.2.5, limited to self-hosted apps using the built-in Node.js server.
Fixed versionsPatch in 15.5.16 and 16.2.5 for this CVE. Note: Vercel's coordinated May 7, 2026 security rollup later recommended moving to 15.5.18 or 16.2.6 to clear the broader batch of May 2026 Next.js issues.
Exposure and scanning realityScanner coverage is emerging rather than mature. ProjectDiscovery added a Nuclei template, but internet-exposure estimates floating around for Next.js origins are third-party Shodan-based claims and not independently verified here.
Disclosure timelineGitHub advisory published 2026-05-06; NVD published 2026-05-13; GitHub advisory updated 2026-05-14. Vendor coordinated release note landed 2026-05-07.
Reporter / publisherPrimary advisory published by Vercel / Next.js maintainers via GitHub Security Advisory GHSA-c4j6-fc7j-m34r.
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to HIGH (7.7/10)

The decisive factor is that this is still unauthenticated remote SSRF against an app origin, which is a real pivot path to cloud metadata and internal services when exposed. The score comes down because the vulnerable population is meaningfully narrowed to self-hosted built-in Node.js deployments and the impact is highly dependent on what the origin can reach.

HIGH Affected-version and deployment-scope determination
MEDIUM Real-world exposure prevalence across enterprise Next.js fleets
MEDIUM Exploit-activity assessment beyond public PoC availability

Why this verdict

  • Unauthenticated remote path: no auth, no user click, and no complicated exploit chain to trigger the SSRF primitive
  • Deployment friction lowers the score: only self-hosted Next.js using the built-in Node.js server is affected; Vercel-hosted deployments are out, which materially shrinks the exposed population
  • Blast radius is conditional: the bad outcome depends on what the app tier can reach, whether metadata is hardened, and whether egress controls block internal destinations

Why not higher?

This is not direct RCE and not a universal Next.js flaw. An attacker still needs a reachable vulnerable origin and something valuable behind it such as permissive metadata, localhost admin ports, or weakly trusted internal APIs; those prerequisites are where many enterprise deployments add real friction.

Why not lower?

Do not over-downgrade it just because it is 'only SSRF.' Unauthenticated SSRF from an internet-facing app tier is exactly how attackers steal cloud credentials, hit localhost-only admin surfaces, and pivot into internal services without ever touching user auth.

05 · Compensating Control

What to do — in priority order.

  1. Block upgrade traffic where unused — If the application does not need WebSocket upgrades, deny Connection: Upgrade / Upgrade: websocket at the reverse proxy or load balancer. For a HIGH verdict, deploy this within 30 days; if the origin is internet-exposed and you cannot patch immediately, do it sooner.
  2. Deny metadata and private-range egress — Block app-tier access to 169.254.169.254, localhost admin ports, and unnecessary RFC1918 destinations from the Next.js host or pod. This directly cuts the value of the SSRF even if the bug is still present; for a HIGH verdict, put these egress controls in place within 30 days.
  3. Hide origins behind trusted ingress — Do not expose the built-in Next.js origin directly to untrusted networks; place it behind a hardened ingress or reverse proxy that only forwards the traffic patterns you actually use. For this HIGH finding, prioritize this architectural containment within 30 days if patching has operational delay.
  4. Monitor outbound from Node.js — Alert on the Node.js process initiating connections to metadata IPs, RFC1918 space, localhost service ports, or unusual external destinations immediately after upgrade requests. Detection will not stop the bug, but it shortens dwell time while you work through the 30-day mitigation window.
What doesn't work
  • A generic WAF-only response does not solve this reliably; Vercel explicitly stated these May 2026 advisories cannot be reliably blocked at the WAF layer.
  • Relying on MFA or app auth misses the point because the vulnerable path is pre-auth and unauthenticated.
  • Assuming 'it's behind a reverse proxy' is enough is false; many proxies happily forward upgrade traffic to the vulnerable origin.
06 · Verification

Crowdsourced verification payload.

Run this on the application host, container, CI workspace, or source repo checkout that contains the Next.js app. Invoke it with python3 verify_next_cve_2026_44578.py /path/to/app and no elevated privileges are required; it reads package.json, lockfiles, and node_modules/next/package.json if present.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# verify_next_cve_2026_44578.py
# Exit codes:
#   0 = PATCHED
#   1 = VULNERABLE
#   2 = UNKNOWN

import json
import os
import re
import sys
from typing import Optional, Tuple


def parse_semver(v: str) -> Optional[Tuple[int, int, int]]:
    if not v:
        return None
    v = v.strip()
    if v.startswith('v'):
        v = v[1:]
    m = re.match(r'^(\d+)\.(\d+)\.(\d+)', v)
    if not m:
        return None
    return tuple(int(x) for x in m.groups())


def cmp_ver(a, b):
    return (a > b) - (a < b)


def is_vulnerable(ver: Tuple[int, int, int]) -> bool:
    return (cmp_ver(ver, (13, 4, 13)) >= 0 and cmp_ver(ver, (15, 5, 16)) < 0) or \
           (cmp_ver(ver, (16, 0, 0)) >= 0 and cmp_ver(ver, (16, 2, 5)) < 0)


def load_json(path: str):
    try:
        with open(path, 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception:
        return None


def get_version_from_package_json(app_dir: str) -> Optional[str]:
    data = load_json(os.path.join(app_dir, 'package.json'))
    if not data:
        return None
    for section in ('dependencies', 'devDependencies', 'peerDependencies', 'optionalDependencies'):
        deps = data.get(section, {})
        if isinstance(deps, dict) and 'next' in deps:
            return str(deps['next'])
    return None


def get_installed_version(app_dir: str) -> Optional[str]:
    nm = os.path.join(app_dir, 'node_modules', 'next', 'package.json')
    data = load_json(nm)
    if data and isinstance(data.get('version'), str):
        return data['version']
    return None


def clean_spec(spec: str) -> Optional[str]:
    if not spec:
        return None
    spec = spec.strip()
    m = re.search(r'(\d+\.\d+\.\d+)', spec)
    return m.group(1) if m else None


def main() -> int:
    if len(sys.argv) != 2:
        print('UNKNOWN - usage: python3 verify_next_cve_2026_44578.py /path/to/app')
        return 2

    app_dir = sys.argv[1]
    if not os.path.isdir(app_dir):
        print(f'UNKNOWN - path not found: {app_dir}')
        return 2

    installed = get_installed_version(app_dir)
    declared = get_version_from_package_json(app_dir)

    version_source = None
    version_str = None

    if installed:
        version_source = 'installed node_modules/next/package.json'
        version_str = installed
    elif declared:
        cleaned = clean_spec(declared)
        if cleaned:
            version_source = 'declared package.json dependency spec'
            version_str = cleaned

    if not version_str:
        print('UNKNOWN - could not determine Next.js version from node_modules or package.json')
        return 2

    ver = parse_semver(version_str)
    if not ver:
        print(f'UNKNOWN - could not parse Next.js version: {version_str}')
        return 2

    if is_vulnerable(ver):
        print(f'VULNERABLE - detected Next.js {version_str} from {version_source}; CVE-2026-44578 affects >=13.4.13 <15.5.16 and >=16.0.0 <16.2.5 in self-hosted apps using the built-in Node.js server')
        return 1

    print(f'PATCHED - detected Next.js {version_str} from {version_source}; version is outside the vulnerable ranges for CVE-2026-44578')
    return 0


if __name__ == '__main__':
    sys.exit(main())
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: identify every self-hosted Next.js service running the built-in Node.js server, verify version, and separate anything internet-reachable from internal-only deployments. For this HIGH verdict, the noisgate mitigation SLA is ≤30 days: if you cannot patch immediately, block unused WebSocket upgrades, remove direct origin exposure, and deny metadata/private-range egress first; then complete the actual framework update within the noisgate remediation SLA of ≤180 days. If a given app is publicly exposed and cloud-hosted, do not wait for the long tail of the remediation window—treat it as the front of the queue.

Sources

  1. GitHub Security Advisory GHSA-c4j6-fc7j-m34r
  2. Patch commit c4f6908
  3. Vercel changelog: Next.js May 2026 security release
  4. NVD entry
  5. Horizon3 analysis
  6. CISA Known Exploited Vulnerabilities Catalog
  7. FIRST EPSS API documentation
  8. ProjectDiscovery nuclei-templates release notes
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.