Back to Blog

CVE-2026-94545: Next.js Image Generation Crosses a Trust Boundary

Sythe Labs Team

An image-generation route can become a server-side code-execution path. The September 22 advisory for CVE-2026-94545 rates the affected Next.js implementation at CVSS v4 9.5. Exposure requires Node.js ImageResponse from next/og and attacker-controlled values reaching SVG content, attributes, or styles. An affected dependency version is the start of the investigation; you still have to trace the input.

The useful detail is in the upstream serialization patch. A value intended to remain text could become part of the SVG document's structure. The security question is what happens when the next component reads that document.

The version range needs a reachable rendering path

The Next.js advisory, published September 22, identifies versions >=16.2.0 <16.3.6 and gives 16.3.6 as the fix. It excludes the Edge implementation and applications that never pass attacker-controlled values into the affected SVG fields.

Start your review at the deployed image route. Find where ImageResponse is constructed, establish which runtime serves it, and follow the values supplied to the SVG. Review stored user-editable content as well as request parameters. A value loaded from your own database can still originate with someone outside your organization.

That last step is application analysis, not an additional vendor-confirmed exploit condition. It is how you decide whether the condition in the advisory exists in your code. Record the route and the input source rather than marking every installation equally exposed.

The serializer let values become structure

Satori turns application content into SVG. Its September 22 advisory describes insufficient escaping that allows crafted values to be interpreted as markup. The consequence depends on the component consuming the generated SVG.

Here is a small, exact excerpt from the September 22 patch to src/handler/preprocess.ts:

-  if (typeof node !== 'object') return String(node)
+  if (typeof node !== 'object') return escapeXMLText(node)

The old branch converted a primitive into a string without escaping it for XML text. The replacement applies the escaping function before the value joins the document. This excerpt illustrates one repair, not a complete local hotfix.

The same patch strengthens buildXMLString in src/utils.ts: it validates XML names and escapes attribute values. Other rendering paths move through that builder, while src/handler/expand.ts rejects caller-supplied style properties reserved for internal use. Regression tests cover these boundaries. Those changes are visible in the public diff; we inspected them, but did not execute the test suite or reproduce code execution.

The general failure is easy to carry into other software. A value is data when one component receives it. After serialization, another component may parse it as instructions or document structure. The serializer owns that transition. Familiar JSX syntax at the call site does not establish what this separate output path does with the value.

The downstream consumer determines the impact

Next.js's September 22 security update attributes the possible code execution to the SVG escaping defect combined with vulnerabilities in other upstream dependencies. It says the release upgrades those dependencies. The announcement does not describe the complete downstream exploit chain, so the serializer diff should not be presented as independent proof of every step to code execution.

This distinction also explains the different severity labels. The Satori advisory rates its own issue moderate, at CVSS v4 5.3, and lists versions >=0.0.27 <0.33.5. The Next.js integration receives the critical rating. Both advisories were published September 22 and use the same CVE identifier; they describe different impact contexts.

When reviewing your own rendering pipeline, follow the output as carefully as the input. Identify the process that consumes the generated document and what authority that process has. This is especially relevant when a small convenience feature shares a runtime with the rest of an application. A route's product importance does not determine the privileges of the process serving it.

Upgrade the deployed application and keep the evidence

Use the vendor's September 22 release guidance. Update an affected Next.js application to the fixed release or a later supported version containing the fix, rebuild, and redeploy it. The same announcement offers 15.5.26 for related hardening and explicitly says Next.js 15.x is not affected by this RCE.

If you consume Satori directly, its advisory identifies 0.33.5 as the patched version. It gives no complete workaround beyond upgrading and advises against rendering attacker-controlled content while an update is pending. A hand-written sanitizer should not be represented as equivalent to the upstream fix.

For the application owner, the useful completion record is the deployed artifact and its dependency version, followed by a check that the image route still behaves as intended. Keep ordinary text and special-character cases in that check. A changed lockfile establishes what was committed; separately establish what the running service contains.

As of September 24, the vendor sources reviewed here do not report exploitation in the wild. That is a limit of the reviewed evidence, not assurance that exploitation has not occurred.

The decision in front of your team is concrete: identify whether untrusted values reach this renderer, remove that path while patching if necessary, and verify the updated application is the one serving requests.

Sythe Seconds

Get the next insight in your inbox.

Research from our team, practical compliance guidance, and the latest from Sythe Labs. Straight to your inbox.

By subscribing, you agree to receive Sythe Seconds. Unsubscribe anytime. Privacy policy