If you ran npm audit on a Next.js app in the last two weeks, there's a decent chance sharp showed up as high severity, with three advisories stacked on it. You didn't install sharp. And if you're on Next 16.2, npm audit fix won't make it go away.
The newest of the three is GHSA-wq5f-xc86-pv6w, published 2026-09-30: a use-after-free in the librsvg library sharp bundles to read SVG files. We installed the affected versions, read what Next.js actually sends to sharp, and ran npm audit fix the way a create-next-app project would.
TL;DR
sharp below 0.35.5 bundles a vulnerable librsvg (CVE-2026-96889). Next's built-in image optimizer never hands SVG to sharp, so next/image on its own isn't the path. Your own upload code is: sharp(buffer).resize() decodes an SVG no matter what the file is called. On Next 16.0 to 16.2, npm audit fix can't reach the patched sharp. Use an override, block the SVG loader, or move to Next 16.3.8+.
What the advisory says
As of 2026-10-14, sharp's advisory reads, in short:
- Affected:
sharpbelow 0.35.5. Fixed: 0.35.5, published to npm on 2026-09-27, which bundles librsvg 2.63.2. - Severity: High, CVSS v4 8.9.
- Impact: "possible remote code execution (RCE) on glibc-based Linux" when "certain runtime-specific conditions apply". The advisory doesn't spell those conditions out.
- Workaround:
sharp.block({ operation: ["VipsForeignLoadSvg"] }), which stops sharp decoding SVG. - It also notes the official Node.js binaries aren't built as position-independent executables, which it recommends for avoiding RCE.
The upstream bug, per the Debian security tracker, is a librsvg use-after-free "when processing an SVG document containing nested XML inclusions (Xincludes) with duplicate entity declarations". In other words, it takes a crafted SVG. An ordinary JPEG can't trigger it.
OSV lists the record as published 2026-10-06. That's when it entered the advisory database, a week after GitHub published it, which is why some scanners only started flagging it recently.
We checked the bundled versions ourselves with sharp.versions:
| sharp | libvips | librsvg | Status |
|---|---|---|---|
| 0.34.5 | 8.17.3 | 2.61.2 | affected |
| 0.35.4 | 8.18.6 | 2.62.91 | affected |
| 0.35.5 | 8.18.7 | 2.63.2 | fixed |
Why it's in your project
Next.js declares sharp as an optional dependency, so npm install pulls it in quietly. Which sharp you get depends on your Next version. We read the published manifests on 2026-10-14:
| next | sharp range it accepts | Can it resolve 0.35.5? |
|---|---|---|
| 15.4.11 | ^0.34.3 | No |
| 15.5.0 to 15.5.23 | ^0.34.3 | No |
| 15.5.24 | ^0.34.3 || ^0.35.3 | Yes |
| 15.5.25 to 15.5.27 | ^0.34.3 || ^0.35.4 | Yes |
| 16.0.11, 16.1.7 | ^0.34.4 | No |
| 16.2.12 (last 16.2) | ^0.34.5 | No |
| 16.3.8, 16.4.0 | ^0.35.4 | Yes |
So an app on Next 16.0 to 16.2, or any 15.x before 15.5.24, is stuck on sharp 0.34.x no matter how many times you reinstall. On the newer versions, an existing lockfile still pins whatever sharp it resolved last time until you run npm update sharp. A fresh npm install next@16.2.12 resolves sharp 0.34.5, and npm audit reports three advisories against it: this one, the earlier libvips batch, and the libheif one.
Why npm audit fix doesn't fix it
create-next-app writes next into package.json as an exact version, no caret. We confirmed that in the create-next-app 16.4.0 source. npm audit fix only moves packages within the ranges you've declared, and an exact pin is a range of one.
Here's what we got on a project with "next": "16.2.12":
sharp <=0.35.5-rc.1
Severity: high
sharp : Vulnerability in librsvg dependency CVE-2026-96889
fix available via npm audit fix --force
Will install next@16.4.0, which is outside the stated dependency range
After the dry run, the lockfile still said sharp 0.34.5. The tool's only offer is a framework upgrade. The same audit also flags next@16.2.12 itself as critical, including the AVIF remote code execution in Next's image optimizer that came in through sharp's bundled libheif. That's a real decision on an app an AI scaffolded for you, not something to --force at midnight.
Does it actually reach your app?
This is the part that matters, and the answer splits cleanly in two.
next/image: no
We read dist/server/image-optimizer.js in next 16.2.12. Before anything touches sharp, Next sniffs the file type from its first bytes. If it's SVG and images.dangerouslyAllowSVG is off (the default), Next returns a 400. If you've turned that option on, SVG is in Next's bypass list and gets served back unprocessed. Either way, the image optimizer never asks sharp to decode an SVG. Next's own docs say the same thing in plainer words: "By default, Next.js does not optimize SVG images."
That's true for this particular CVE only. Don't read it as "/_next/image is safe": the AVIF advisory earlier this cycle was a bundled-library bug in sharp that did reach Next's optimizer, because Next does optimize AVIF.
Your own upload code: yes, by default
This is the pattern AI tools write constantly for profile pictures and product images:
import sharp from 'sharp';
export async function POST(req) { const file = (await req.formData()).get('avatar'); const buffer = Buffer.from(await file.arrayBuffer()); const resized = await sharp(buffer).resize(256, 256).webp().toBuffer(); // save resized... }
sharp picks the decoder from the file's contents, not its name or the browser's Content-Type. We fed a plain SVG through that code on sharp 0.35.4: metadata() reported format: 'svg' and resize() happily produced a PNG. Calling the upload avatar.png changes nothing.
That code runs wherever your route runs: a VPS, a Docker container, or a serverless function on Vercel, Netlify or Lambda. Those are all Linux on glibc as far as we can tell, which is the platform the advisory names.
Checking the format with sharp first doesn't help. A common "validation" step is const { format } = await sharp(buffer).metadata() and rejecting anything that isn't JPEG or PNG. We confirmed that metadata() goes through the same SVG loader: once we blocked it, metadata() on an SVG failed with "Input buffer contains unsupported image format". So by the time metadata() tells you it's an SVG, librsvg has already read it. Sniff the magic bytes with something like file-type before the buffer reaches sharp.
The 5-minute check
See which sharp you have. Run npm ls sharp. Anything below 0.35.5 is affected.
Check your Next version. If npm ls next shows 16.0.x, 16.1.x or 16.2.x, or any 15.x before 15.5.24, you can't reach 0.35.5 through Next's range.
Find your own sharp calls. Run grep -rn "from 'sharp'\|require('sharp')" app src lib pages. No hits means your exposure to this CVE is essentially limited to next/image, which doesn't decode SVG. Hits mean read on.
For each hit, ask where the buffer comes from. A file a user uploaded, or an image URL a user supplied, is attacker-controlled. Your own static assets aren't.
Three ways to fix it
1. Upgrade Next (the clean fix). next 16.3.8 and later accept sharp ^0.35.4, so a normal install resolves 0.35.5. It's a minor-version jump on a framework, so run your build and click through the app afterwards.
2. Override sharp (a stopgap if you can't upgrade yet). Add this to package.json, then npm install:
{ "overrides": { "sharp": "0.35.5" } }
Then confirm with npm ls sharp, which should print sharp@0.35.5 overridden. We checked that Next 16.2.12's image optimizer still loads with it, but we didn't run a full production build, so run yours. It also does nothing about the critical advisories against next itself, which is why upgrading is the real fix.
3. Block the SVG loader (belt and braces). If your app never needs to read SVG, tell sharp so, once, at startup:
import sharp from 'sharp'; sharp.block({ operation: 'VipsForeignLoadSvg' });
We tested it: after this call, an SVG buffer fails with "Input buffer contains unsupported image format", and JPEGs still decode normally. It's the advisory's own workaround, and it's worth keeping even after you upgrade, since this is sharp's third bundled-library advisory since late July.
Whichever you pick, add magic-byte validation in front of sharp for uploads. It costs a few lines, and it means the next librsvg or libheif bug has to get past your allowlist before it ever reaches a decoder.
Why AI-built apps hit this more
Two habits line up. Coding assistants reach for sharp(buffer).resize() the moment you ask for avatar uploads, usually with no format check, or with a metadata() check that runs too late. And scaffolds pin Next exactly, so the app stays on whatever Next existed the day it was generated. Any app scaffolded on Next 16.0 to 16.2 is on a version whose range can't reach the fixed sharp, with an audit warning the obvious command can't clear.
What is the sharp librsvg vulnerability?
GHSA-wq5f-xc86-pv6w, published 2026-09-30. sharp versions below 0.35.5 bundle a librsvg with CVE-2026-96889, a use-after-free triggered by SVG files with nested XIncludes and duplicate entity declarations. sharp's advisory says it can lead to possible remote code execution on glibc-based Linux under certain runtime conditions. Fixed in sharp 0.35.5, which bundles librsvg 2.63.2.
I never installed sharp. Why does npm audit report it?
Next.js lists sharp as an optional dependency, so npm installs it for you. On next 16.2.12 a fresh install resolves sharp 0.34.5, and npm audit lists three advisories against it, this one included.
Why doesn't npm audit fix clear it?
Because Next 16.0 to 16.2 only accept sharp 0.34.x, and create-next-app pins next to an exact version. npm audit fix stays inside your declared ranges, so it leaves sharp at 0.34.5 and tells you the fix needs npm audit fix --force, which installs a newer Next outside your stated range.
Does next/image pass SVG files to sharp?
No. We read the image optimizer in next 16.2.12. It detects the type from the file's first bytes, rejects SVG with a 400 unless dangerouslyAllowSVG is on, and even then returns SVG unprocessed. The exposure is your own code calling sharp on uploads.
How do I fix it without upgrading Next?
Either add an npm override that forces sharp 0.35.5, or call sharp.block with VipsForeignLoadSvg at startup so sharp refuses SVG input entirely. Upgrading to next 16.3.8 or later is the clean fix, since those releases accept sharp 0.35.x.
Shipped an upload feature?
Scan your app for exposed endpoints, missing headers and the other things an attacker checks first.