Talk to us

Cybersecurity

Next.js on Node.js: Four Layers, Four Ways In

Aerovant Technologies Security Team

A terminal running next build beside Next.js and Node.js logos and a red warning triangle, with the words Security Alert.

When teams think about Next.js security, they think about their own code: an API route without an auth check, a form that trusts its input. Those bugs are real. But over the past year, the most serious Next.js vulnerabilities were not in anyone’s application code.

They were in the layers underneath: the Next.js framework, React Server Components, the Node.js runtime and the C libraries that process images. One of them scored a perfect CVSS 10.0 and was exploited within hours of disclosure. Two more critical flaws were patched in Next.js on 14 October 2026, and the Node.js runtime fixed its own remote code execution bug a week later.

If you run a Next.js product, marketing site or internal tool on your own servers or containers, read on.

What happened

This is not one incident but a run of them. Each hit a different layer, and each was fixed upstream, outside the code most teams review.

DateEvent
21 Oct 2026Node.js fixes 10 CVEs across 26.x, 24.x and 22.x, including a Brotli decoder out-of-bounds write that permits remote code execution (CVE-2026-111497)
14 Oct 2026Next.js 16.4.1 and 15.5.28 fix two critical RCEs (SVG image processing, CVE-2026-96889, also tracked as GHSA-2464-fhr4-w9xw; use cache typed arrays, GHSA-673q-mjm6-r5xr) and a Server Actions DoS
Sep 2026A next/og flaw lets attacker-controlled text change the SVG it generates (reported by The Hacker News)
Aug 2026A libheif bug, reached through sharp, allows code execution via crafted AVIF images (reported by The Hacker News)
7 May 2026Next.js 16.2.6 and 15.5.18 ship 13 advisories: middleware and proxy bypass, SSRF, cache poisoning, XSS and DoS
30 Apr 2026Node.js 20 reaches end of life; it receives no further upstream security fixes
3–5 Dec 2025React2Shell (CVE-2025-55182, CVSS 10.0) is disclosed on 3 Dec; Datadog records scanning that evening and 800+ attacking IPs by 5 Dec
21 Mar 2025Next.js middleware bypass (CVE-2025-29927) is disclosed

The pattern is the detail that matters. Image processing alone produced three code execution flaws in three months, and none of them was in Next.js’s own code.

How Next.js and Node.js fit together

Next.js is not a server on its own. It is a framework that runs inside a Node.js process, and Node.js in turn calls native C and C++ libraries for compression, TLS and image processing. Every request travels down through these layers and back up.

A simple way to picture it is a restaurant. The browser is the customer and the CDN is the front door. Node.js is the building and its utilities. Next.js is the kitchen layout and order system, React Server Components are the recipes, and the native libraries are the specialist machines at the back. A fire in any room closes the restaurant, however good the recipes are.

What each layer does, and where untrusted data enters it:

LayerWhat it doesWhere outside data gets in
Next.js frameworkMiddleware (now also called proxy), routing, Route Handlers, the image optimiser at /_next/imageEvery request; middleware runs first, and many teams put authentication there
React Server ComponentsRenders on the server and streams to the browser in React’s Flight format; Server Actions and use cache use the same formatServer Action arguments, which arrive from the browser as Flight data
Node.js runtimeHTTP parsing, TLS, DNS, zlib/Brotli decompression, outbound fetch() (Undici)Request bodies, compressed responses from servers you fetch, hostnames you resolve
Native librariessharp → libvips → librsvg (SVG), libheif (AVIF); OpenSSL for TLSUploaded or remote images, certificates

Two misconceptions cause most of the trouble:

  • “Server code is private.” Every exported Server Action is a public HTTP endpoint that anyone can call with any arguments, whether or not your UI shows a button for it.
  • “Middleware protects my routes.” Middleware is a convenience layer. If it can be skipped, every route behind it opens.

Some routes can run on the lighter Edge runtime instead of full Node.js. It has no native addons, so sharp-based image bugs do not apply there, but it still parses untrusted input. Know which runtime each route uses.

How the attacks work

Five attack paths cover the incidents above. Each one hits a different layer.

Middleware bypass: skipping the bouncer

Next.js used an internal header, x-middleware-subrequest, to avoid running middleware twice. In CVE-2025-29927:

  1. The attacker adds x-middleware-subrequest to a request, with the value Next.js expects for that version.
  2. Next.js treats the request as an internal subrequest and skips middleware.
  3. Any page whose only authentication check lived in middleware is served to the attacker.

Fixed in 15.2.3, 14.2.25, 13.5.9 and 12.3.5. The May 2026 release fixed four more High-severity middleware and proxy bypasses.

React2Shell: hostile serialised data

CVE-2025-55182 was an unsafe deserialisation flaw in React’s Flight decoder:

  1. The attacker sends a crafted request to a React Server Components endpoint.
  2. The server-side decoder accepts values that should only ever come from React itself.
  3. Those values steer execution, and the attacker runs code on the server.

A fresh create-next-app project was exposed by default. Datadog saw payloads that downloaded shell scripts, stole environment files and dropped binaries.

Poisoned images: native library bugs

In CVE-2026-96889 (GitHub advisory GHSA-2464-fhr4-w9xw: one bug, two IDs), a memory bug in librsvg, which Next.js reaches through sharp, can lead to code execution on glibc-based Linux:

  1. The attacker gets a crafted SVG in front of the image pipeline, for example as an uploaded avatar.
  2. Next.js hands it to sharp, which calls librsvg to render it.
  3. librsvg mishandles memory while parsing the crafted shapes.
  4. The attacker’s code runs inside the Node.js server process.

Next.js does not optimise SVGs by default. According to The Hacker News, exposure needs images.dangerouslyAllowSVG turned on or next/og running on the Node.js runtime; the official advisory states only the glibc Linux condition.

Runtime bugs: compressed data that writes back

In Node.js CVE-2026-111497, the bundled Brotli decoder has an out-of-bounds write that permits remote code execution. Node’s built-in fetch() decompresses Brotli responses automatically, so a feature that fetches user-supplied URLs (link previews, webhooks, importers) can be enough:

  1. The attacker submits a URL that points to a server they control.
  2. Your Next.js Route Handler or Server Action calls fetch() on it.
  3. Their server replies with Content-Encoding: br and a crafted body.
  4. The vulnerable decoder writes out of bounds while decompressing it.

The same release fixed a dns.resolve() bug that truncated hostnames at a NUL byte, so the name an SSRF filter checked could differ from the one resolved, plus two TLS hostname verification bypasses.

Unprotected Server Actions: the forgotten endpoint

This one is in your code, and it is the most common. Every exported Server Action is reachable by HTTP POST.

TypeScript · vulnerable
// Vulnerable: any logged-in user can delete any invoice
'use server';
export async function deleteInvoice(invoiceId: string) {
  await db.invoice.delete({ where: { id: invoiceId } });
}
TypeScript · fixed
// Fixed: authenticate, validate input, scope the query to the owner
'use server';
import { z } from 'zod';
import { requireUser } from '@/lib/dal';

const Input = z.object({ invoiceId: z.string().uuid() });

export async function deleteInvoice(raw: unknown) {
  const user = await requireUser();
  const { invoiceId } = Input.parse(raw);
  await db.invoice.deleteMany({ where: { id: invoiceId, ownerId: user.userId } });
}

What an attacker gets

Code execution as the user running the Node.js process. In most Next.js deployments that means everything in process.env: database URLs, auth signing secrets such as NEXTAUTH_SECRET, payment and AI API keys, and often cloud credentials. With a session signing secret, an attacker can forge logins for any user. With cloud credentials, they can move from the web tier into storage and databases.

Who is affected

ComponentStatusAction
Next.js 16.xAffected through 16.4.0 (SVG RCE, use cache RCE, Server Actions DoS)Upgrade to 16.4.1
Next.js 15.xAffected through 15.5.27 (SVG RCE, Server Actions DoS)Upgrade to 15.5.28 and make sure sharp is 0.35.5+
Next.js 10.x–14.xSVG RCE affects 10.0.0 onwards; no patch on these linesUpgrade to 15.5.28 or 16.4.1
react-server-dom-*19.0.0–19.3.0 affected by the use cache issue upstreamUpgrade through the patched Next.js release
Node.js 26.x / 24.x / 22.xAffected below 26.12.1 / 24.22.1 / 22.23.4Upgrade and restart
Node.js 20.x and olderEnd of life, affected, no upstream fixMove to 22 or 24

The sharp caveat. Next.js 15.5.28 still accepts the vulnerable sharp 0.34.x, and an upgrade over an existing install can leave it in place. Version 16.4.1 requires 0.35.5. On 15.x, always check npm ls sharp.

The scanner caveat. At release, the use cache and Server Actions advisories had no CVE and were missing from the feed npm audit uses. A clean audit is not proof you are patched.

Is it being exploited?

SourceWhat they report
Datadog Security LabsReact2Shell: scanning from about 22:00 UTC on 3 Dec 2025; 800+ attacking IPs by 5 Dec; weaponised payloads observed
The Hacker NewsOctober 2026 Next.js flaws: no public reports of exploitation as of 15 Oct
SecurityOnlineOctober 2026 Node.js flaws: the Node.js team reports no exploitation in the wild and no confirmed public proof of concept

React2Shell is the warning. It went from disclosure to mass scanning in hours. The October flaws sit in the same layers, so treat “no attacks yet” as a head start, not a reason to wait.

Why this hits Indian startups and SMEs hard

Next.js has become a default choice for Indian SaaS startups, D2C brands and agency-built products. Three patterns make these bugs especially risky here.

  • The agency-built app nobody owns. An agency delivered the product, the contract ended, and nobody upgrades its dependencies. It may still be on Next.js 13 or 14, or on Node.js 18 or 20, which get no fix.
  • Self-hosted containers on a VPS or EC2. A Next.js app in Docker on EC2, Lightsail, DigitalOcean or Hetzner is patched by nobody unless you rebuild the image. Managed platforms patch their runtime; a self-hosted container keeps the old one.
  • One .env holding everything. The same app often carries production database credentials, payment keys and broad cloud access keys in environment variables. Code execution in the Node process is enough to take them all.

If your answer to “which Next.js and Node.js versions is our app on?” is “I’d have to ask someone”, start with the next section.

Check your exposure in 10 minutes

On Vercel, Netlify or another managed platform, check the Node.js version in your project settings and confirm the platform has applied the October runtime patches. Projects on Node.js 20 must move to 22 or 24.

For a self-hosted app, run these from the project root and inside the deployed image:

bash
# 1. Framework, React and image library versions actually installed
npm ls next react react-dom sharp

# 2. Node.js runtime version
node --version

# 3. Is SVG optimisation switched on?
grep -rn "dangerouslyAllowSVG" next.config.*

# 4. Cache Components and Server Actions in use?
grep -rn "cacheComponents" next.config.*
grep -rln "'use cache'\|'use server'" app/ src/ 2>/dev/null

# 5. Containers: which Node.js and Next.js are inside each running image?
docker ps -q | xargs -I{} docker exec {} node --version

Watch out for:

  • The lockfile is not the server. A patched package.json on a laptop means nothing until a new build is running in production. Check inside the deployed image.
  • More than one app. Monorepos, admin panels and marketing sites often carry their own next dependency. Check each one.
  • Old base images. A node:20 or unpinned node:lts image built months ago still contains the old runtime. Rebuild from a fresh, pinned base image.

Fix it

Patching is the only complete fix. Everything else only buys time.

1. Patch, rebuild, redeploy, restart

bash
# Next.js 16
npm install next@16.4.1

# Next.js 15.5 — also pin sharp, because 15.5.28 still accepts sharp 0.34.x
npm install next@15.5.28 sharp@^0.35.5

# Confirm
npm ls next sharp

Force a fixed sharp even when another package pulls an older one:

package.json
{
  "overrides": { "sharp": "^0.35.5" }
}

Then upgrade Node.js to 26.12.1, 24.22.1 or 22.23.4, rebuild the container with npm ci, redeploy, and restart every Node process. A running process keeps the old code in memory.

On Next.js 13 or 14, or Node.js 20 or older, there is no patch on your line. Upgrade, or take the app off the internet until you can.

Internet-facing apps come first, and among those, apps that accept uploads or fetch user-supplied URLs.

2. If you cannot patch today

These settings reduce exposure but do not make an app safe.

next.config.js
// next.config.js
module.exports = {
  images: {
    dangerouslyAllowSVG: false, // the default: keep SVGs out of the optimiser
    remotePatterns: [{ protocol: 'https', hostname: 'cdn.example.com' }],
  },
};

Also:

  • Strip internal headers at the edge, such as x-middleware-subrequest, which a browser should never send.
  • Reject Content-Encoding: br on inbound requests at your proxy if you do not need it.
  • Validate every URL your server fetches: HTTPS only, an allowlist of hosts, no control characters in the hostname, and no private or link-local IPs.
  • Rate-limit POST requests to Server Action routes and alert on sustained high CPU in Node processes.
  • Put a WAF in front, and make sure the origin accepts traffic only from it.

The use cache RCE and the Server Actions DoS have no workaround. Only the upgrade closes them.

3. What not to do

  • Don’t rely on middleware alone for authorisation. Check the user again where data is read or changed.
  • Don’t treat a clean npm audit as proof. Two of the October advisories were missing from its feed at release.
  • Don’t update package.json and stop. Without a rebuild and redeploy, production still runs the old code.
  • Don’t assume your platform or agency has patched. Ask, and get a yes in writing.

Detect and verify

There are no published indicators of compromise for the October 2026 flaws. Hunt for the side effects that code execution in Node.js usually leaves. Treat these as leads, not proof.

Signs worth investigating:

  • Node.js processes spawning shells or tools such as sh, bash, curl, wget or nc.
  • Crashes and restarts, such as segmentation faults or repeated container restarts, in services that process images or fetch external URLs.
  • Unusual requests to /_next/image for SVG sources, or bursts of POST requests carrying a Next-Action header.
  • Outbound connections from the app to unfamiliar IPs.
  • New or changed files in writable directories such as .next/cache or upload folders.

After patching, verify:

  • npm ls next sharp and node --version show fixed versions inside every deployed image.
  • Every Node process was restarted after the update.
  • If you found any of the signs above, rotate every secret the app holds: database credentials, session signing secrets, payment and API keys, and cloud credentials. A patched app can still have an attacker inside.

The lesson beyond these CVEs

These advisories will be patched and forgotten. The conditions that make them dangerous will not.

  • Your app is the top of a tall stack. Next.js, React, Node.js and sharp each need watching and patching, not just your own code.
  • You cannot patch what you don’t know you run. Keep an inventory of every app, its Next.js, Node.js and sharp versions, and who owns it.
  • End-of-life software is a standing liability. Next.js 13 and 14 and Node.js 20 got no fix this time, and will get none next time.
  • Defence in depth still matters. Authorise next to the data, keep secrets out of the browser, give the app least-privilege credentials, and restrict its outbound traffic.
  • Someone has to be watching. React2Shell went from disclosure to mass scanning in hours. Only monitoring catches an attack that lands before your patch does.

How Aerovant can help

If you are unsure which Next.js and Node.js versions run in your environment, or whether last week’s traffic was more than noise, our team can help:

  • Exposure check: identify internet-facing Next.js and Node.js apps, their versions and how they are deployed.
  • Patch and hardening support for self-managed servers, cloud VMs and containers on AWS.
  • Compromise assessment: log review and secret-rotation planning for apps that were exposed.
  • VAPT and Managed SOC to find the next weak point before an attacker does, and to watch for it after hours.

Write to admin@aerovanttech.com or get in touch.

This article reflects public information as of 23 October 2026. Details may change as vendors publish further analysis; always follow the official Next.js, React and Node.js advisories.

Sources

All insights

Worried about your own exposure?

Tell us what you run. We will tell you plainly what to check first.