Threat Overview
Vercel disclosed CVE-2026-94545 on September 22. The flaw affects Next.js ImageResponse when attacker-controlled values reach SVG content, attributes, or styles during image generation on the Node.js runtime. ImageResponse uses Satori to produce SVG before final image rendering. Under vulnerable conditions, crafted input can lead to server-side code execution. This is code-path dependent: simply running Next.js is not sufficient.
References
- The Hacker News, September 23, 2026.
- Netlify, September 22, 2026: https://www.netlify.com/changelog/2026-09-22-nextjs-imageresponse-vulnerability/
- Vercel/Next.js advisory for CVE-2026-94545, September 22, 2026.
Impacted Systems
Next.js applications using next/og ImageResponse on the Node.js runtime with attacker-controlled values reaching SVG content, attributes or styles. Vercel reporting identifies Next.js 16.2.0 through 16.3.5, fixed in 16.3.6. Netlify also documents 15.5.26 as a patched release for its platform guidance. Edge ImageResponse is not affected by the vulnerable Node.js path. Direct Satori users should update to 0.33.5+.
Why this matters
Next.js is broadly deployed on Internet-facing web applications. A server-side code-execution path reachable through image-generation functionality can turn a social-preview route into application-host compromise.
Exploitation Status
No confirmed exploitation in the wild was identified as of September 23. The issue is publicly disclosed and patched, so it should be treated primarily as urgent patch and exposure validation rather than an active-exploitation incident.
What this hunt looks for
Image and Open Graph routes, encoded SVG input, Node child processes, Node-created scripts, outbound network activity, new destinations, persistence behavior, and Linux application-log fallbacks.
Required logs
Web/WAF telemetry in CommonSecurityLog, Defender XDR DeviceProcessEvents, DeviceFileEvents and DeviceNetworkEvents, and Linux Syslog where available.
First Pass – Image and Open Graph Routes
CommonSecurityLog
| where TimeGenerated >= ago(30d)
| where RequestURL has_any ("opengraph-image","twitter-image","_next/image")
| project TimeGenerated,SourceIP,DestinationIP,RequestMethod,RequestURL,DeviceAction,Message
| order by TimeGenerated descEncoded SVG in Image Requests
CommonSecurityLog
| where TimeGenerated >= ago(30d)
| where RequestURL has_any ("opengraph-image","twitter-image","_next/image")
| where RequestURL has_any ("%3csvg","%3c","<svg","data:image/svg","%22","%27")
| project TimeGenerated,SourceIP,DestinationIP,RequestMethod,RequestURL,DeviceAction,Message
| order by TimeGenerated descNode Spawning Shells
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName in~ ("node","node.exe")
| where FileName in~ ("sh","bash","dash","cmd.exe","powershell.exe","pwsh.exe","python","python3","curl","wget")
| project Timestamp,DeviceName,AccountName,InitiatingProcessCommandLine,FileName,ProcessCommandLine,SHA256
| order by Timestamp descNode-Created Executables and Scripts
DeviceFileEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName in~ ("node","node.exe")
| where ActionType in~ ("FileCreated","FileModified")
| where FileName endswith ".sh" or FileName endswith ".py" or FileName endswith ".ps1" or FileName endswith ".exe" or FileName endswith ".dll"
| project Timestamp,DeviceName,ActionType,FileName,FolderPath,SHA256,InitiatingProcessCommandLine
| order by Timestamp descNode Outbound Network Activity
DeviceNetworkEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName in~ ("node","node.exe")
| project Timestamp,DeviceName,InitiatingProcessAccountName,InitiatingProcessCommandLine,RemoteUrl,RemoteIP,RemotePort
| order by Timestamp descNew Node Destinations
let Known=DeviceNetworkEvents
| where Timestamp between (ago(30d)..ago(2d))
| where InitiatingProcessFileName in~ ("node","node.exe")
| summarize by DeviceId,RemoteIP,RemoteUrl;
DeviceNetworkEvents
| where Timestamp >= ago(2d)
| where InitiatingProcessFileName in~ ("node","node.exe")
| join kind=leftanti Known on DeviceId,RemoteIP,RemoteUrl
| project Timestamp,DeviceName,InitiatingProcessCommandLine,RemoteUrl,RemoteIP,RemotePort
| order by Timestamp descNode Persistence Behavior
DeviceProcessEvents
| where Timestamp >= ago(30d)
| where InitiatingProcessFileName in~ ("node","node.exe","sh","bash","cmd.exe","powershell.exe")
| where FileName in~ ("systemctl","crontab","schtasks.exe","sc.exe","reg.exe")
| project Timestamp,DeviceName,AccountName,FileName,ProcessCommandLine,InitiatingProcessFileName,InitiatingProcessCommandLine
| order by Timestamp descLinux Web App Syslog Fallback
Syslog
| where TimeGenerated >= ago(30d)
| where SyslogMessage has_any ("next","node","opengraph-image","twitter-image")
| where SyslogMessage has_any ("bash","sh -c","curl ","wget ","python ","systemctl","cron")
| project TimeGenerated,Computer,HostName,ProcessName,SeverityLevel,SyslogMessage
| order by TimeGenerated descDetection Notes
No vendor exploit IOCs were identified. HTTP queries are heuristic because routes and WAF parsing vary. Node child-process execution is high-value but not unique. The most reliable first step is application inventory and code/configuration validation for ImageResponse with untrusted SVG input.