Safeguard
Vulnerability Analysis•

Next.js next/og RCE (CVE-2026-94545): Is Your OG Image Route Exposed?

A satori escaping bug made the Node.js ImageResponse in next/og an RCE path. Only routes that put attacker-controlled values into SVG are reachable. Fixed in 16.3.6.

Safeguard Security Team
6 min read

On 22 September 2026 Vercel published GHSA-vcvr-r3jv-pc5j and shipped Next.js 16.3.6. The advisory, rated Critical at CVSS v4 9.5, says the Node.js ImageResponse implementation exported from next/og "is affected by an upstream vulnerability" that "can lead to remote code execution". The same day the satori project published its own advisory for the escaping bug underneath. Both carry CVE-2026-94545.

This is a good case for reachability thinking. Plenty of Next.js 16 apps import next/og, but the advisory is specific about which ones can actually be hit.

What's affected

The next package from 16.2.0 up to, but not including, 16.3.6. The fix is in 16.3.6. Next.js 15.x is not listed as affected.

The upstream issue is GHSA-wx4j-mvgx-mqwp in satori, the library that turns JSX into SVG for OG images. Satori versions from 0.0.27 up to, but not including, 0.33.5 "do not properly escape certain values before including them in generated SVG output", which lets crafted values be read as SVG markup. Satori rates its own advisory Moderate (CVSS v4 5.3) because, in its words, "the impact depends on how the generated SVG is consumed." Inside Next.js, that consumption is what turns it into an RCE.

The Next.js advisory narrows the blast radius in three ways:

  • Only the Node.js ImageResponse is affected. Routes using the Edge implementation are not.
  • Only routes that pass attacker-controlled values into SVG content, attributes or styles during image generation are affected.
  • Routes that render only constants or trusted data are not affected.

The advisory's own example is a route handler that reads a query parameter and drops it into an SVG title:

import { ImageResponse } from 'next/og'

export async function GET(request: Request) {
  const value = new URL(request.url).searchParams.get('value') ?? ''
  return new ImageResponse(
    <svg width="1200" height="630">
      <title>{value}</title>
    </svg>
  )
}

How to check if you're exposed

Start with the version. Anything from 16.2.0 to 16.3.5 needs the upgrade:

npm ls next
# or
pnpm why next

Then find every place that builds an image with ImageResponse. In App Router projects that usually means opengraph-image and twitter-image files plus any route handler that generates images:

grep -rln "from 'next/og'\|from \"next/og\"" app src pages 2>/dev/null
find . -path ./node_modules -prune -o \( -name "opengraph-image.*" -o -name "twitter-image.*" \) -print

For each file, answer two questions.

Which runtime does it use? Look for a segment config line. If the file exports runtime = 'edge', the advisory says it is not affected. If there is no runtime export, the route runs on the Node.js runtime by default.

grep -rn "export const runtime" $(grep -rln "next/og" app src 2>/dev/null)

Where do the rendered values come from? Trace every variable that ends up inside the JSX you pass to ImageResponse. The obvious attacker-controlled sources are query strings and dynamic route params such as a slug. Less obvious ones are database fields that users can edit: a post title, a display name, a product description. If a user can type it and it reaches SVG content, attributes or styles, treat the route as reachable.

A route that renders params.slug from a [slug] segment is in scope even if you never meant it to be public, because anyone can request /blog/anything/opengraph-image.

What to do now

  1. Upgrade to Next.js 16.3.6 or later. Later 16.x releases also carry the fix. Rebuild and redeploy; a lockfile change alone does nothing for a running server.
  2. Check for a direct satori dependency. If any package in your tree resolves satori on its own, make sure it is 0.33.5 or later: npm ls satori.
  3. If you cannot upgrade today, follow the advisory's workaround. Stop passing attacker-controlled values into SVG content, attributes or styles in Node.js ImageResponse routes. Replacing a user title with a fixed string is ugly, but it closes the path.
  4. Consider moving image routes to the Edge runtime only if that fits your app. The advisory lists Edge as unaffected, but switching runtimes has its own constraints, so treat it as a design decision, not a hotfix.
  5. Review logs for odd OG requests. Look for unusually long query strings or markup characters hitting opengraph-image and image routes before you patched.

Why it matters

The upstream library and the framework disagree on severity, and both are right. Satori produces a string. Whether a malformed string is cosmetic or catastrophic depends on what the caller does with it next. Next.js consumes that SVG on the server, so the same bug scores 5.3 in one advisory and 9.5 in the other.

That is the core of reachability. A scanner that matches next 16.3.5 will flag every app on that version. The useful question is narrower: does this app run a Node.js ImageResponse route that renders user-controlled input? Many marketing sites render only static titles. Many SaaS apps render user-generated names on share cards. Those two groups need very different urgency, even on the same version.

Try it yourself

Take one Next.js 16 repo and list every ImageResponse call. For each one, write down the runtime and the source of every rendered variable. Mark a route "reachable" only if a user-controlled value reaches the image. Then compare that short list to the single version-based finding your dependency scanner reports.

Click through it at your own pace, or open it full screen.

Quick check

Is an opengraph-image file that only renders a hard-coded site name affected?

Per the advisory, no. Applications that do not pass attacker-controlled values into SVG content, attributes or styles are not affected. Upgrade anyway, since the next change to that file may add a dynamic value.

Why does satori rate the same bug Moderate while Next.js rates it Critical?

Satori only generates SVG, and its advisory says impact depends on how that SVG is consumed. The Next.js Node.js ImageResponse consumes it on the server in a way that can lead to code execution, so the framework advisory scores the end-to-end impact.

Which Next.js versions need the fix?

16.2.0 through 16.3.5. Version 16.3.6 contains the fix.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.