Back to Intelligence

Critical Next.js ImageResponse RCE via Crafted SVG — Detection, Hunting, and Remediation Guide

SA
Security Arsenal Team
September 23, 2026
9 min read

On September 22, 2026, Vercel disclosed and patched a critical vulnerability in Next.js that can lead to server-side code execution through ImageResponse — the API developers use to dynamically generate Open Graph (OG) and social preview images at request time. The flaw is triggered when an application passes attacker-controllable values — most commonly text read directly from the request URL (query parameters, route segments) — into the image generation pipeline, which accepts crafted SVG input that escalates to code execution on the server.

This is a defender's nightmare scenario because of where these endpoints live. OG image routes (/api/og, opengraph-image.tsx, twitter-image.tsx) are almost always publicly exposed, unauthenticated, and internet-facing by design — they exist so social media crawlers can hit them. That means the preconditions for exploitation are trivially met on any affected deployment that interpolates user input into the generated image. If your organization runs Next.js applications that generate dynamic social cards with titles, usernames, or any request-derived text, treat this as an urgent patch-and-hunt event.

Technical Analysis

Affected Component

The vulnerable component is ImageResponse, part of the Next.js server runtime (built on the Satori/OG-image rendering stack that converts JSX/HTML-like markup into SVG, then rasterizes it). The rendering pipeline parses SVG content server-side. When attacker-controlled strings flow into that pipeline without sanitization, a crafted SVG payload can break out of the rendering context and achieve code execution in the Node.js server process.

Exploitation Requirements

From a defender's perspective, the attack chain looks like this:

  1. Reconnaissance: The attacker identifies OG image endpoints that reflect request input — e.g., https://target.com/api/og?title=Hello renders "Hello" into the image. These patterns are trivially fingerprintable.
  2. Payload delivery: The attacker submits a request where the reflected parameter contains a malicious SVG structure rather than plain text. Because the input is interpolated into markup that the renderer parses as SVG, the crafted input is interpreted as active content.
  3. Execution: The malicious SVG triggers code execution within the Next.js server process — typically the Node.js runtime hosting the app. From there, the attacker inherits whatever the process can reach: environment variables (often containing database credentials, API keys, JWT secrets), the filesystem, and outbound network access.

The vulnerability requires no authentication. The only precondition is that the application passes attacker-controlled values into ImageResponse. Applications that generate purely static OG images are not exposed.

Exploitation Status

Vercel shipped the fix on September 22, 2026. At the time of this writing, defenders should assume that technical details — and the attack pattern itself (malicious input into a public rendering endpoint) — are easy to weaponize. Public OG endpoints are heavily crawled and indexed, which means vulnerable parameter patterns are discoverable at scale. Do not wait for confirmation of in-the-wild exploitation to patch; the exposure surface is too convenient. Review access logs retroactively — exploitation attempts may predate your patching.

Detection & Response

Detection here has two layers: (1) web-layer telemetry — requests to OG image routes carrying SVG markup or encoded payload strings, and (2) host-layer telemetry — the Node.js server process exhibiting post-exploitation behavior (spawning shells, reading sensitive files, making unexpected outbound connections). The host-layer signals are the higher-fidelity ones: a Next.js server process spawning /bin/sh, curl, or wget is never normal in production.

Sigma Rules

YAML
---
title: Next.js Server Process Spawning Shell or Script Interpreter
id: 4f7c2a91-8e3d-4b5a-9c6f-2d1e0a8b7c34
status: experimental
description: Detects a Node.js/Next.js server process spawning command shells or script interpreters, consistent with post-exploitation activity following server-side code execution via the ImageResponse SVG flaw.
references:
  - https://thehackernews.com/2026/09/critical-nextjs-imageresponse-flaw-can.html
  - https://attack.mitre.org/techniques/T1059/
author: Security Arsenal
date: 2026/09/25
tags:
  - attack.execution
  - attack.t1059
logsource:
  category: process_creation
  product: linux
detection:
  selection_parent:
    ParentImage|endswith:
      - '/node'
      - '/nodejs'
      - '/next-server'
  selection_child:
    Image|endswith:
      - '/sh'
      - '/bash'
      - '/dash'
      - '/zsh'
      - '/python'
      - '/python3'
      - '/perl'
      - '/curl'
      - '/wget'
      - '/nc'
      - '/ncat'
  condition: selection_parent and selection_child
falsepositives:
  - Build tooling or health-check scripts legitimately invoked by the Node process in containerized environments; tune per deployment baseline
level: high
---
title: SVG Payload in Request to Open Graph Image Endpoint
id: 8b3e5d12-6f4a-4c7b-a1d9-3e2f5c8a9b01
status: experimental
description: Detects HTTP requests to Next.js OG image routes containing raw or URL-encoded SVG markup in query parameters, indicative of exploitation attempts against the ImageResponse code execution flaw.
references:
  - https://thehackernews.com/2026/09/critical-nextjs-imageresponse-flaw-can.html
  - https://attack.mitre.org/techniques/T1190/
author: Security Arsenal
date: 2026/09/25
tags:
  - attack.initial_access
  - attack.t1190
logsource:
  category: webserver
detection:
  selection_path:
    cs-uri-stem|contains:
      - '/api/og'
      - 'opengraph-image'
      - 'twitter-image'
      - '/og'
  selection_payload:
    cs-uri-query|contains:
      - '%3Csvg'
      - '<svg'
      - '%3Cscript'
      - '<script'
      - '%3CforeignObject'
      - 'onload='
      - 'javascript%3A'
  condition: all of selection_*
falsepositives:
  - None expected in normal operation; legitimate OG image requests carry plain text titles, not markup
level: critical

The first rule is your highest-fidelity catch: in a well-built production Next.js deployment, the server process should never spawn shells, downloaders, or interpreters. The second rule targets the delivery mechanism at the web layer — plain-text titles do not legitimately contain <svg or <script tokens, so hits here warrant immediate investigation even on patched systems (an attacker probing a patched host is still worth knowing about).

KQL (Microsoft Sentinel / Defender)

This query hunts web-layer delivery attempts across IIS, Apache/Nginx (via CEF/Syslog ingestion), and edge devices logging to CommonSecurityLog, followed by a host-layer query for post-exploitation behavior:

KQL — Microsoft Sentinel / Defender
// Hunt 1: Requests to OG image endpoints carrying SVG/script payloads
let ogRoutes = dynamic(["/api/og", "opengraph-image", "twitter-image", "/og"]);
let payloadTokens = dynamic(["%3Csvg", "<svg", "%3Cscript", "<script", "%3Cforeignobject", "onload=", "javascript%3a"]);
union isfuzzy=true
    (CommonSecurityLog
     | where RequestURL has_any (ogRoutes)
     | where RequestURL has_any (payloadTokens)
     | project TimeGenerated, SourceIP, RequestURL, RequestMethod, DeviceVendor, DeviceProduct),
    (Syslog
     | where SyslogMessage has_any (ogRoutes) and SyslogMessage has_any (payloadTokens)
     | project TimeGenerated, HostIP, Computer, SyslogMessage)
| sort by TimeGenerated desc
;
// Hunt 2: Node.js server processes spawning shells or downloaders (Defender for Endpoint on Linux)
DeviceProcessEvents
| where TimeGenerated > ago(7d)
| where InitiatingProcessFileName has_any ("node", "nodejs", "next-server")
| where FileName in~ ("sh", "bash", "dash", "zsh", "python", "python3", "perl", "curl", "wget", "nc", "ncat")
| project TimeGenerated, DeviceName, InitiatingProcessCommandLine, FileName, ProcessCommandLine, AccountName
| sort by TimeGenerated desc

Velociraptor VQL

Use this artifact for live-response hunting across your Next.js fleet — first for suspicious child processes of the Node runtime, then for node processes holding unexpected outbound connections (data staging or C2 after code execution):

VQL — Velociraptor
-- Hunt for Node.js processes spawning shells/tools or holding suspicious outbound connections
LET suspicious_children = SELECT Pid, Ppid, Name, CommandLine, Exe, Username, CreateTime
FROM pslist()
WHERE CommandLine =~ '(sh|bash|curl|wget|nc|ncat|python|perl)'
  AND Name =~ '^(sh|bash|dash|curl|wget|nc|ncat|python|python3|perl)$'

LET node_conns = SELECT Pid, Name, CommandLine, RemoteAddress, RemotePort, Status
FROM netstat()
WHERE Name =~ 'node'
  AND RemotePort NOT IN (443, 80, 5432, 3306, 6379, 27017)
  AND RemoteAddress !~ '^(127\.|10\.|172\.(1[6-9]|2[0-9]|3[01])\.|192\.168\.)'

SELECT * FROM suspicious_children
UNION ALL
SELECT Pid, NULL AS Ppid, Name, CommandLine, RemoteAddress AS Exe, NULL AS Username, NULL AS CreateTime
FROM node_conns

Verification and Remediation Script

Run this against your application repositories and build environments to identify vulnerable Next.js versions, confirm whether ImageResponse consumes request-derived input, and upgrade:

Bash / Shell
#!/bin/bash
# Next.js ImageResponse SVG RCE - exposure audit and remediation helper
set -euo pipefail

echo "=== [1] Installed Next.js version ==="
if [ -f package.json ]; then
  grep -E '"next"' package.json || echo "next not found in package.json"
fi
if [ -f node_modules/next/package.json ]; then
  INSTALLED=$(grep -E '"version"' node_modules/next/package.json | head -1)
  echo "Installed: $INSTALLED"
fi

echo ""
echo "=== [2] ImageResponse usage in codebase ==="
grep -rn "ImageResponse" --include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" . 2>/dev/null | grep -v node_modules || echo "No ImageResponse usage found."

echo ""
echo "=== [3] DANGEROUS: request input flowing into ImageResponse ==="
echo "Review any hit below — these indicate attacker-controlled values reaching the renderer:"
grep -rn -B5 -A15 "ImageResponse" --include="*.tsx" --include="*.ts" . 2>/dev/null \
  | grep -v node_modules \
  | grep -E "searchParams|req\.query|params\.|nextUrl|url\.search" || echo "No obvious request-input interpolation found."

echo ""
echo "=== [4] Upgrade Next.js to the September 22, 2026 fixed release ==="
echo "Run: npm install next@latest   (or: pnpm up next / yarn upgrade next)"
echo "Then rebuild and redeploy ALL environments — the fix only applies to redeployed server bundles."
echo ""
echo "=== [5] Post-upgrade verification ==="
echo "After upgrade, re-run step [3]. Any remaining request-input flows must be sanitized (strict allowlist of characters, length caps) before reaching ImageResponse."

Remediation

  1. Upgrade Next.js immediately. Vercel released the fix on September 22, 2026. Update to the latest patched Next.js release (npm install next@latest) and rebuild and redeploy every environment — the vulnerable code lives in your server bundle, so a dependency bump without redeployment changes nothing.
  2. Audit every ImageResponse call site. Search your codebase for ImageResponse and trace every value passed into it. Any value derived from searchParams, route params, request headers, or request bodies is your exposure. If you cannot patch immediately, remove request-input interpolation or take the dynamic OG route offline as a stopgap.
  3. Sanitize at the boundary. Even after patching, treat user input entering a rendering pipeline as hostile: enforce strict character allowlists (alphanumeric and basic punctuation), cap input length, and never pass raw request strings into markup-generating APIs.
  4. Review the vendor advisory. Consult Vercel's official security advisory and release notes referenced in the disclosure (see The Hacker News coverage) for the exact fixed version numbers applicable to your release line.
  5. Retroactively hunt. Pull 30–90 days of access logs for your OG image routes. Search for requests containing %3Csvg, %3Cscript, foreignObject, or abnormally long query strings. Any hit justifies a full IR scoping of that host: environment variable exposure, outbound connection review, and credential rotation.
  6. Rotate secrets on any host you cannot clear. Successful exploitation executes code with the Next.js process's privileges — which in most deployments means access to every environment variable, including database credentials and signing keys. If you find evidence of probing or exploitation, rotate those secrets; do not assume they weren't read.
  7. Add structural controls. Place OG image generation behind a WAF rule blocking markup tokens in query strings, run the Node.js process under a least-privilege user with no shell access, and egress-filter outbound traffic from application servers to break post-exploitation C2 and data staging.

The broader lesson: server-side rendering pipelines that parse markup (SVG, HTML, PDF) are code execution surfaces, and features built to be hit by anonymous internet crawlers are the first place attackers will look. Treat every such endpoint as a pre-authentication attack surface in your threat model, and wire detection around the renderer process — not just the web layer.

Related Resources

Security Arsenal Red Team Services AlertMonitor Platform Book a SOC Assessment pen-testing Intel Hub

Is your security operations ready?

Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.