If you run a Next.js site on version 16.2 or later and it generates social share images, update to 16.3.6 today. That is the required action and it takes a minute.

The rest of this article is about the part the one-liner hides, and it is unusual. This vulnerability is two bugs in two different projects, written in two different languages, and only one of them has been fixed in a release you can actually install. The other one is sitting in the current published version of a library that arrives with every default Next.js install and with every Astro site that optimizes an image.

Everything below was checked on September 25, 2026. Where a fact could be taken from a primary source we took it from the primary source and we say which one. Several of the findings are ours, from reading published bundles and from installing the packages and asking them what they contain. They are labelled where they appear.

Update, September 26, 2026. Re-checked, and nothing has moved. The latest tag on npm for sharp is still 0.35.4, published August 26. 0.35.5-rc.0 is still the only build carrying librsvg 2.63.2 and it is still tagged next, so a default npm install next@16.3.6 still pulls the unpatched renderer. api.osv.dev still returns an empty result for next@16.3.5 and for sharp@0.35.4. cveawg.mitre.org still returns CVE_RECORD_DNE for CVE-2026-94545, four days after the release that fixed it. The librsvg identifier, CVE-2026-96889, is published there and was last updated September 25. The advice below is unchanged, including the September 30 Next.js release to plan for.

Update, September 28, 2026. This is now fixed, and a plain install gets the fix. sharp 0.35.5 was promoted to the latest tag on npm on September 27 at 13:46:24 UTC, carrying @img/sharp-libvips-* 1.3.4, published ninety five minutes earlier at 12:11:24 UTC. We installed it on a clean machine today and asked it what it contains: rsvg reports 2.63.2, which is above the top of the advisory’s affected range. Then we did the test that matters. A fresh npm install next@16.3.6 in an empty directory today resolves sharp to 0.35.5 with rsvg 2.63.2 underneath it, because Next.js pins sharp@^0.35.4 and the caret now reaches the fixed build. The second half of the chain, the part this article was written about because it was not fixed in anything you could install, is fixed in the default install. Nothing else has moved: cveawg.mitre.org still returns CVE_RECORD_DNE for CVE-2026-94545 six days on, and api.osv.dev still returns an empty result for next@16.3.5. So the software is correct and the vulnerability databases are still silent, which is the same gap this article documents, now with the patch on the other side of it. If you ran step 3 last week and found 2.62.91, run it again.

What shipped

Next.js 16.3.6 and 15.5.26 went out on September 22, 2026, out of band, ahead of a scheduled security release that Vercel has since announced for September 30.

We did not take the timing from the announcement. The npm registry records a publication timestamp for every version, and the sequence that afternoon is worth reading in order:

Time (UTC, September 22) Package Version
02:24:55 librsvg (GNOME) 2.62.4, the stable-branch backport
10:32:50 @img/sharp-libvips-linux-x64 1.3.4-rc.0
14:24:36 sharp 0.35.5-rc.0
16:01:32 satori 0.33.5
16:19:00 next 16.3.6
17:03:27 next 15.5.26

Five projects, one afternoon, fifteen hours from end to end. Two of those releases are still release candidates three days later, which is the whole second half of this article.

The identifier is CVE-2026-94545, credited to Raghav Maheshwari and Rafael B. Dias. It carries a CVSS 4.0 base score of 9.5 critical on the Next.js advisory, vector CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H, and 5.3 moderate on the satori advisory for the same identifier. Both numbers are right, and the gap between them is the story.

The bug, in satori’s own source

Satori is the library that turns JSX into an SVG. Next.js uses it inside ImageResponse, the thing that draws your Open Graph card. The published npm package is a minified bundle, so a plain diff of dist/index.js gives you seven lines of unreadable soup.

It also ships source maps, and source maps carry sourcesContent: the original TypeScript, verbatim. So we pulled the sources back out of both versions and diffed those instead.

npm pack satori@0.33.4 satori@0.33.5
# then read sourcesContent out of dist/index.js.map in each

Seven files changed. The one that matters is src/utils.ts, and here is the whole vulnerability in two lines:

  for (const [k, _v] of Object.entries(attrs)) {
    if (typeof _v !== 'undefined') {
-     attrString += ` ${k}="${_v}"`
+     assertValidXMLName(k, 'attribute')
+     attrString += ` ${k}="${escapeXMLAttribute(_v)}"`
    }
  }

buildXMLString is the function every part of satori calls to produce a piece of SVG. It took an attribute value and interpolated it into markup between two quote characters, with nothing in between. Any value containing a double quote closed the attribute early and everything after it became markup.

The patch adds two things. escapeXMLAttribute runs values through escape-html, which was already a dependency and was already being used on text content but not on attributes. assertValidXMLName validates element and attribute names against XML’s own name grammar, with a comment that explains why the names could not simply be escaped:

// Mirrors React's XML-compatible attribute-name validation. Names cannot be
// escaped, so validate them before interpolating them into markup.

The other six files are the same fix applied to the places that were building markup by hand rather than going through buildXMLString at all. In src/builder/rect.ts, for example, this:

(opacity !== 1 && !useFillOpacity ? `<g opacity="${opacity}">` : '') +

became a buildXMLString('g', { opacity }, content) call, which now escapes. There were five such hand-built <g> tags across the builder and text modules. Every one of them is gone.

The largest change is in src/handler/preprocess.ts, which handles an inline <svg> element inside your JSX. That code was building an entire SVG document as a template string, with unescaped attributes and unescaped text, then encoding the result into a data: URL. Text nodes went through String(node) with no escaping at all. It now routes through buildXMLString like everything else, and it adds one more guard:

if (typeof type !== 'string') {
  throw new Error('Only intrinsic elements are supported inside <svg>')
}

There is also a change in src/handler/expand.ts that is easy to miss and worth understanding. Style properties beginning with an underscore are satori’s own internal channel. Before the patch they were copied straight into the serialized style. Now:

if (prop.startsWith('_')) {
  throw new Error(`Invalid style property: ${JSON.stringify(prop)}`)
}

That closes a second door: a style object built from user input could set an internal property and reach the serializer through a path the attribute escaping does not cover.

The satori advisory gives the affected range as 0.0.27 and above, below 0.33.5. We wanted to know what was special about 0.0.27, so we pulled the sources out of it and out of 0.0.26 the same way.

buildXMLString is in both, character for character, unescaped interpolation included. It was published that way on August 11, 2022, in a version the advisory does not cover.

What 0.0.27 added, eleven days later, is translateSVGNodeToSVGString and the data:image/svg+xml serializer that goes with it: the code that takes an inline <svg> out of your JSX and turns the whole subtree into a document. That is the reachable path, and it is what sets the boundary. The unsafe function is older than the advisory’s range. The route to it is not. That distinction is the useful one to carry into any dependency audit: a range start usually marks the day a bug became reachable, not the day it was written.

We reproduced it

This took about five minutes and it is worth showing because it explains, better than a CVSS vector does, why this is a big deal on a route you think of as harmless.

The advisory’s own example of the vulnerable pattern is a page that puts a query parameter into an SVG title:

const value = new URL(request.url).searchParams.get('value') ?? ''
return new ImageResponse(<svg><title>{value}</title></svg>)

We built the equivalent element by hand, passed it through satori directly with a real font, and printed the SVG document that came out. Against 0.33.4, with value set to a string containing a closing tag:

<svg xmlns="http://www.w3.org/2000/svg"><title></title><rect width="99" height="99" fill="red"/><title></title></svg>

The <rect> is a real element. It was text a moment ago.

Against 0.33.5, the same input, same script:

<svg xmlns="http://www.w3.org/2000/svg"><title>&lt;/title&gt;&lt;rect width=&quot;99&quot; height=&quot;99&quot;
fill=&quot;red&quot;/&gt;&lt;title&gt;</title></svg>

Text stays text. That is the fix working, and it is the entire fix on the Next.js side.

Now hold on to one thing about that first output. Drawing a red rectangle on somebody’s share card is a defacement, and that is the small version of this. The real consequence is that an attacker who can put arbitrary elements into that document gets to hand a document of their own composition to whatever renders it next.

Why the range starts at exactly 16.2.0

The advisory says Next.js >= 16.2.0 < 16.3.6 is affected, and that the Edge implementation is not affected. It does not say why, and the reason turns out to matter more than the range does.

Next.js does not depend on @vercel/og from npm. It vendors a compiled copy into dist/compiled/@vercel/og/. We downloaded four Next.js releases and read the version out of that directory:

Next.js bundled @vercel/og references sharp
16.1.0 0.7.2 no
16.2.0 0.11.1 yes
16.3.5 0.11.1 yes
16.3.6 0.11.1 yes
15.5.25 0.7.2 no
15.5.26 0.7.2 no

This is our finding and we have not seen it stated anywhere. The affected range does not start at 16.2.0 because a bug was introduced there. The satori bug is years older than that. It starts at 16.2.0 because that is the release where the bundled @vercel/og went from 0.7.2 to 0.11.1, and 0.11.1 is the version that started rendering with sharp.

Here is the relevant code, verbatim, out of next@16.3.6’s own dist/compiled/@vercel/og/index.node.js:

let pngBuffer;
if (sharp) {
  pngBuffer = await sharp(new TextEncoder().encode(svg)).resize(options.width).png().toBuffer();
} else {
  const resvgJS = new resvg.Resvg(svg, {
    fitTo: { mode: "width", value: options.width }
  });
  ...
}

and the line above it that decides which branch you get:

var _sharp;
async function getSharp() {
  if (_sharp) { return _sharp; }
  try {
    _sharp = (await import("sharp")).default;
  } catch (e) {
    return void 0;
  }
  return _sharp;
}

Read that try/catch carefully. Whether your server rasterizes the generated SVG with a native C library or with a WebAssembly module depends on whether a dynamic import("sharp") resolves at runtime. There is no configuration for it, no warning, and no log line. It is a silent capability check.

That is also the answer to “why is Edge not affected” and “why is Next.js 15 not affected by the remote code execution”. Edge has no sharp and never takes that branch. Next.js 15 ships @vercel/og 0.7.2, which has no reference to sharp anywhere in its bundle, so it always uses the WebAssembly renderer. Both still had the satori injection bug. Neither had anywhere dangerous to send the injected document. Vercel’s own note on 15.5.26 says exactly that, in one clause: “Version 15.5.26 includes related hardening, but Next.js 15.x is not affected by the remote code execution issue.”

We confirmed the hardening reached both branches by searching the shipped bundles for three strings that exist only in the patched satori:

Bundle Invalid XML Invalid style property Only intrinsic elements...
next 15.5.25 absent absent absent
next 15.5.26 present present present
next 16.3.5 absent absent absent
next 16.3.6 present present present

The second half of the chain

An attacker with arbitrary SVG markup and a native renderer needs one more thing: a bug in the renderer. There is one, it is three days old, and it belongs to a project most web developers have never installed on purpose.

CVE-2026-96889 is a use-after-free in librsvg, GNOME’s SVG rendering library, reported by Rafael B. Dias, the same researcher credited on the satori advisory. The RustSec advisory describes the mechanism precisely enough to quote:

While libxml2 is expanding an internal entity, a recursive XInclude can parse another document that declares an entity with the same name. Both parses use the same XmlState entity map on the librsvg side. entity_insert() replaces the first entry, whose Drop implementation calls xmlFreeNode(). The outer xmlCtxtParseEntity() then keeps using the freed 144-byte xmlEntity.

In plain terms: an SVG document can pull in a second SVG document, the second one can redefine an XML entity the first one is still in the middle of expanding, and librsvg frees a structure that libxml2 is still holding a pointer to. A 144-byte allocation, freed and then reused, with the attacker choosing the contents of both documents. That is a classic heap-grooming primitive, and it is why the Next.js advisory says the injection “could lead to remote code execution due to vulnerabilities in other upstream dependencies.”

The librsvg affected range, from the advisory’s own machine-readable data, has two intervals: everything below 2.62.4, and everything from 2.62.90 up to 2.63.2. The second interval is the development series that became 2.63. The fix is commit 8a1b0cd319e9af2d1e9cf878081dd77f227a0504, and the release timeline from GNOME’s own download server, read off the last-modified header on each tarball, is:

librsvg Published
2.62.91 August 14, 2026, 23:38 GMT
2.63.0 September 8, 2026, 21:47 GMT
2.63.1 September 18, 2026, 23:27 GMT
2.63.2 (fix) September 18, 2026, 23:57 GMT
2.62.4 (backport) September 22, 2026, 02:24 GMT

Note the thirty minutes between 2.63.1 and 2.63.2. That is what a security release looks like when it is cut on top of a version that went out half an hour earlier.

The part that is not fixed

Here is where this stops being a story about patching and starts being a story about what “patched” means.

We installed the patched Next.js on a clean machine this morning. Nothing clever, no flags, exactly what a developer would type:

npm install next@16.3.6 react react-dom
node -e "const s=require('sharp');console.log(s.versions.rsvg, s.versions.heif, s.versions.vips)"

The output:

2.62.91 1.23.2 8.18.6

librsvg 2.62.91. The advisory’s affected range is 2.62.90 up to 2.63.2. That version sits inside it.

This is not an accident of our machine. Next.js 16.3.6 declares sharp at ^0.35.4 in its optionalDependencies, and optional dependencies install by default. The current latest on npm for sharp is 0.35.4, published August 26, 2026. The build that carries the fixed librsvg is 0.35.5-rc.0, published September 22 at 14:24 UTC, and it is tagged next, not latest. A caret range does not select a prerelease. So the standard install of the patched framework pulls the library with the unpatched renderer, and will keep doing so until sharp cuts a stable 0.35.5.

The difference between the two, from the packages themselves:

sharp@0.35.4 (latest) sharp@0.35.5-rc.0 (next)
librsvg 2.62.91, in the affected range 2.63.2, the fix
libheif 1.23.2 1.23.5
libxml2 2.15.3 2.15.4
libvips 8.18.6 8.18.6

We also wanted to know whether the precondition is even reachable through sharp’s front door, or whether librsvg as libvips configures it has XInclude switched off. So we wrote a benign test: an outer SVG that uses xi:include to pull in a data: URI containing a second SVG that draws a black square, rendered through sharp() from a plain buffer, counting dark pixels in the output.

sharp 0.35.4  | rsvg 2.62.91 | dark pixels: 1600 of 1600 | XInclude expanded: true
sharp 0.35.5-rc.0 | rsvg 2.63.2  | dark pixels: 1600 of 1600 | XInclude expanded: true

Two things follow. First, XInclude from a data: URI works out of the box in sharp, with no options set, which is the precondition CVE-2026-96889 needs. Second, the fix does not disable XInclude. It fixes the entity lifetime and leaves the feature on, which is the correct call upstream and means there is no configuration you can set to opt out.

To be clear about what this does and does not mean for a Next.js site today. If you are on 16.3.6, satori will no longer let a visitor’s text become markup, so the door into librsvg through next/og is shut. The memory-corruption bug underneath is still installed on your server, and it is still reachable by anything else that hands sharp an SVG.

Which is the more useful number, 7.8 or 9.5

The same underlying flaw carries a Red Hat CVSS 3.1 score of 7.8 high, vector AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H, against a Next.js score of 9.5 critical with AV:N ... UI:N.

Both are correct and the difference is not a disagreement. Red Hat scored librsvg the way librsvg is used on a Red Hat system: a desktop library that renders an icon or a thumbnail from a file a user opened. Attack vector local, user interaction required. Vercel scored the same bug the way it is reachable through a public Open Graph route: attack vector network, no user interaction, because nobody has to open anything. A crawler requesting your share card is the interaction.

This is worth internalizing if you triage by score. A distribution tracker scores a library against the threat model of the distribution. If you have put that library behind an HTTP endpoint, the score in the tracker is not your score. We made the same point from the other direction in the piece on CISA’s risk-based patching directive: published severity is an input, not an answer.

What the tooling tells you, which is nothing

Every check in this section was run today, September 25, on the clean next@16.3.6 install described above.

npm audit: 0 vulnerabilities. On a tree containing next@16.3.5 and sharp@0.35.4, which is the critical-RCE version of Next.js plus the vulnerable renderer, npm audit reports found 0 vulnerabilities. We control-tested the same command against lodash@4.17.11 and it returned seven advisories including a critical, so the query path works and the silence is real.

OSV: nothing. A query to api.osv.dev for next@16.3.5 returns an empty vulnerability list. So does satori, and so does @img/sharp-libvips-linux-x64. A query for sharp@0.35.4 returns nothing, although four advisories exist for older sharp versions, so the package is modelled in the database and this version simply is not flagged.

No CVE record. CVE-2026-94545 returns CVE_RECORD_DNE from the CVE Program’s own API. The identifier is in use on two GitHub advisories and in a dozen vendor write-ups, and there is no record behind it. The librsvg identifier, by contrast, was published properly by Red Hat at 19:40:14 UTC on September 23.

Ubuntu has the librsvg one and has not triaged it. Ubuntu’s security tracker records CVE-2026-96889 as published September 24, priority medium, with the librsvg package marked needs-triage on every supported release from xenial through resolute. That is the expected state two days in, and it is the entry to watch if you also run librsvg outside Node.

Not in CISA’s catalogue. We pulled the Known Exploited Vulnerabilities feed today, catalog version 2026.09.24, 1,723 entries, released September 24 at 19:00:55 UTC. Neither CVE-2026-94545 nor CVE-2026-96889 is listed. That is the expected answer, since no exploitation has been reported for either, and it is the right place to check rather than assume.

If this pattern feels familiar it is because we documented the identical shape four weeks ago, with the identical library: npm audit missed the critical libheif overflow that reached Next.js through sharp. Same package, same silence, different C library underneath. The reason is structural rather than anybody’s fault. npm’s advisory database models JavaScript packages and their JavaScript dependencies. sharp is a thin wrapper around a prebuilt binary that statically links roughly thirty C libraries, and none of them is a node in the graph npm audits.

What to do

1. Update Next.js. If you are on 16.2.0 or later, go to 16.3.6 or later. If you are on 15.x, 15.5.26 gets you the hardened satori even though 15 was never exposed to the code-execution path.

npm install next@16.3.6   # 16.x
npm install next@15.5.26  # 15.x

Vercel has announced a scheduled release for September 30 covering nine further vulnerabilities, one critical, so plan a second window next week rather than treating this as done.

2. If you use satori directly, go to 0.33.5. It is not only a Next.js dependency. Anything drawing images from JSX on a server, including a number of Astro and Nuxt OG-card integrations, pulls it in.

3. Find out what your sharp actually contains. This is the check almost nobody runs and it takes one line:

node -e "const s=require('sharp');console.log(JSON.stringify(s.versions,null,1))"

An rsvg of 2.62.91, or anything below 2.62.4, or anything from 2.62.90 up to but not including 2.63.2, is the affected library. A heif of 1.23.2 is also three security releases behind, which we come back to below.

4. Decide whether you can wait for sharp 0.35.5. There is no stable release that fixes this yet. Three honest options, in the order we would consider them:

  • Wait, and make sure you actually upgrade when it lands. Reasonable for most sites, because with Next.js 16.3.6 in place the route that made this reachable is closed. Put a reminder somewhere that will survive the week.
  • Pin the release candidate. npm install sharp@0.35.5-rc.0 gets you librsvg 2.63.2 today. It is a release candidate, so test your image pipeline before it reaches production. We would do this on a site that accepts image uploads and not on one that does not.
  • Install without sharp. If your app does not use next/image optimization, npm install --omit=optional leaves sharp out and next/og falls back to the WebAssembly renderer, which is the same code path Edge and Next.js 15 use. Check what else breaks first.

5. If your site accepts file uploads, look at SVG specifically. This is the part that has nothing to do with Next.js and is the reason we wrote at this length. Any application that takes an uploaded image and runs it through sharp to make a thumbnail is handing attacker-controlled bytes to librsvg, because sharp accepts SVG as an input format by default:

node -e "console.log(require('sharp').format.svg.input)"
# { file: true, buffer: true, stream: true, fileSuffix: [ '.svg', '.svgz', '.svg.gz' ] }

There is no framework bug in the middle of that path. The user hands you the document directly. If you do not need SVG uploads, reject them on content type and on magic bytes rather than on file extension, because .svgz is a gzipped SVG and will not look like one. If you do need them, this is the case for pinning the release candidate.

6. Check your distribution packages separately. librsvg is not only an npm concern. It renders icons and thumbnails across GNOME, it sits behind ImageMagick’s SVG delegate, and Red Hat’s own record lists librsvg2 and glycin-loaders on RHEL 10. Your server’s package manager and your node_modules are two different inventories and both need the answer.

A note for people who are not running Next.js

If you are an owner reading this because your developer sent it to you, the short version is that your site is almost certainly fine and the useful question is not about this bug.

Two of the three links in this chain are libraries nobody chose. Nobody sat in a planning meeting and decided to depend on a GNOME SVG renderer from 2001. It arrived inside a package that arrived inside a framework, and the only reason anybody knows which version is installed is that we ran a command to ask.

The question worth asking your developer is not “are we patched for this one”. It is “what is the command that tells us what we are actually running, and who runs it”. On a site we build the answer is a build that fails on its own checks, a dependency audit we run on a schedule, and a person whose job it is to read the output. We wrote up what that costs and what it covers in the piece on what a Toronto small business website costs to build and run.

We also checked our own house while writing this, because it would be poor form not to. This site generates its social cards with sharp at build time from hand-built SVG, which is the same rendering path. Two things make it uninteresting to an attacker: the only text that reaches the card comes from our own Markdown front matter rather than from a visitor, and it goes through an escaping function on the way in. We still upgraded, because “no untrusted input today” is a statement about today.

Retro note on the libheif article

Four weeks ago we wrote that sharp@0.35.4 was the fix for a critical libheif heap overflow, and at the time it was. It is now the wrong advice, and since it is our advice we should say so plainly here as well as on that post.

sharp@0.35.4 bundles libheif 1.23.2, released August 25. libheif has shipped three security releases since: 1.23.3 on September 1, which fixes a heap buffer overflow write rated critical in the uncompressed mixed-interleave decoder along with eight other issues, 1.23.4 on September 6, and 1.23.5 on September 21 with seven more CVEs. The current stable sharp carries none of them. The release candidate carries all of them.

That is the same lag, in the same package, in a different bundled library, thirty days later. It is the strongest argument we can make for the check in step 3 above. The npm version number tells you what the JavaScript wrapper is. It tells you almost nothing about the thirty C libraries doing the actual work, and those are where the memory-corruption bugs live.

What we could not verify

Whether the chain has been exploited. We have seen no report of exploitation of either CVE, and neither is in CISA’s catalogue as of version 2026.09.24. Published proof-of-concept work exists for the librsvg use-after-free. Absence of reports is not absence of attempts.

Whether the use-after-free is reliably exploitable for code execution on a given target. The advisories say “could lead to” and “potentially”. We did not attempt exploitation and we would not publish it if we had. The 144-byte allocation and attacker control of both documents are what make the claim credible rather than theoretical, and that is as far as we will go.

When sharp 0.35.5 will be released as stable. The release candidate went out on September 22. There is no published date for the stable release and no changelog entry for 0.35.5 on sharp’s documentation site yet. Our reading of the gap is that it is an ordinary release-candidate soak and not a decision to leave it, but that is a reading.

Whether other renderers in the chain are affected. We tested the librsvg path because that is what sharp uses and what our XInclude check demonstrated. We did not audit the WebAssembly resvg renderer that Edge and Next.js 15 use. “Not affected by this” is not “audited and clear”.

Whether every hand-built markup site in satori was found. The patch converts five template-string tags to escaped calls, and the researchers found those by reading. We diffed the same sources and found no sixth, but a negative result from reading a diff is weak evidence.

The exact @vercel/og version in Next.js 16.1.9. That tarball did not extract cleanly for us and we left it out of the table rather than guess. The 16.1.0 and 16.2.0 data points establish the boundary either way.

The short version

A flaw in satori let text that a visitor supplied become live SVG markup on your server. In Next.js 16.2 and later, that markup was handed to a native C renderer with a three-day-old use-after-free in it, and the result is code execution. Next.js 16.3.6 fixes the first half. The second half is fixed in librsvg 2.63.2, which reaches npm only in a sharp release candidate, so the standard install of the patched framework still carries the vulnerable renderer today.

Update Next.js. Then run the one-line command in step 3 and find out what your image library is actually made of, because the answer is not in your package.json and your audit tool will not tell you.

If you would rather not be the person tracking a GNOME library’s point releases to know whether your share cards are safe, that is a reasonable position. We have written about choosing between Astro, Next.js and WordPress and about how npm supply chain attacks actually reach a small business site. If you want us to look at what you are running now, get in touch.

Sources

  • Next.js Security Update for a Critical Upstream Issue, Vercel, September 22, 2026, for the out-of-band release, the patched versions, the statement that Edge ImageResponse is unaffected and the quoted clause about 15.x hardening
  • GHSA-vcvr-r3jv-pc5j, Next.js security advisory, for the critical rating, the CVSS 4.0 score of 9.5 and its vector, the affected range of 16.2.0 up to 16.3.6, the vulnerable code example and the credits to Raghav Maheshwari and Rafael B. Dias
  • GHSA-wx4j-mvgx-mqwp, Satori security advisory, for the moderate rating and CVSS 5.3, the affected range of 0.0.27 up to 0.33.5, and the quoted description of the escaping failure
  • Upcoming Next.js September Security Release, Vercel, September 23, 2026, for the September 30 release covering nine further vulnerabilities
  • satori 0.0.26, 0.0.27, 0.33.4 and 0.33.5 packages, downloaded today, with the original TypeScript recovered from the sourcesContent field of the bundled source map in each, for the seven changed files, the buildXMLString diff, the assertValidXMLName comment, the preprocess.ts rewrite, the expand.ts underscore guard, the identical unescaped buildXMLString in 0.0.26, and the arrival of translateSVGNodeToSVGString in 0.0.27
  • Direct reproduction, run today against satori 0.33.4 and 0.33.5 with an identical script, for the injected <rect> element and its escaped form
  • next 15.5.25, 15.5.26, 16.1.0, 16.2.0, 16.3.5 and 16.3.6 packages, downloaded today, for the bundled @vercel/og versions, the verbatim if (sharp) branch and getSharp() function in dist/compiled/@vercel/og/index.node.js, the presence or absence of the three patched-satori marker strings, and the optionalDependencies entry pinning sharp at ^0.35.4
  • npm registry metadata, pulled today for next, satori, sharp and @img/sharp-libvips-linux-x64, for every publication timestamp in the timeline table and for the current latest and next dist-tags
  • RUSTSEC-2026-0305, via the OSV API, published September 23, 2026, for the quoted mechanism, the 144-byte xmlEntity, the fix commit 8a1b0cd3, and the two affected intervals below 2.62.4 and from 2.62.90 up to 2.63.2
  • CVE-2026-96889, CVE Program record assigned by Red Hat, published 2026-09-23T19:40:14Z, for the CWE-416 classification, the Red Hat severity of Important, the CVSS 3.1 score of 7.8 with its local-vector string, and the affected RHEL packages
  • librsvg issue 1241, GNOME GitLab, for the report by Rafael B. Dias and the reproduction case using xi:include with a data URI
  • GNOME download server, queried today via the release index and the HTTP last-modified header on each tarball, for the publication times of librsvg 2.62.4, 2.62.91, 2.63.0, 2.63.1 and 2.63.2
  • Direct verification, run today: sharp@0.35.4 and sharp@0.35.5-rc.0 installed and queried for sharp.versions; a clean npm install next@16.3.6 and the resolved sharp version underneath it; the XInclude expansion test on both sharp builds; sharp.format.svg.input; npm audit on next@16.3.5 with sharp@0.35.4 and the lodash@4.17.11 control
  • OSV API, queried today for next@16.3.5, sharp@0.35.4, satori and @img/sharp-libvips-linux-x64, and cveawg.mitre.org, which returns CVE_RECORD_DNE
  • Ubuntu security tracker, queried today, for the September 24 publication date, the medium priority and the needs-triage status of librsvg on every supported release
  • Known Exploited Vulnerabilities Catalog, CISA, catalog version 2026.09.24, 1,723 entries, released 2026-09-24T19:00:55Z, pulled today, for the absence of both identifiers
  • libheif releases, for v1.23.3 on September 1, v1.23.4 on September 6 and v1.23.5 on September 21, and for the critical heap buffer overflow in the v1.23.3 security section
  • sharp v0.35.4 changelog, for the six documented changes and the absence of any 0.35.5 entry
  • CVE-2026-94545: From JSX to SVG Injection, Checkmarx, September 23, 2026, for independent confirmation of the affected conditions and that no exploitation has been observed
  • VectorFreed, Rafael B. Dias, for the researcher’s own account of the chain from the satori injection through sharp and libvips into librsvg