Shattered glass scattered across carpet, with the words 'CVE Burden' overlaid, representing the accumulated weight of security vulnerabilities

Why Next.js Has 13x More CVEs Than Express

A team running Express spends less time chasing npm audit alerts than a team running Next.js: fewer dependency warnings, fewer version bumps forced by an advisory, less time reading changelogs to work out whether a patch applies to a given configuration. In any single week the difference is small. Over years it compounds into a measurable operational cost.

The question worth asking is how much of that difference is coincidence and how much is structural, a consequence of how much infrastructure a framework owns versus how much it leaves alone.

Rundown

  • As of August 8, 2026, Google’s OSV database catalogues 64 known vulnerabilities for Next.js and 5 for Express. Counted the same way on the same day, that is roughly 13 times more.
  • Severity separates them further than volume does. 28 of Next.js’s 64 advisories, 44%, are rated High or Critical. Express tops out at CVSS 6.1, an open redirect, with nothing in the authorization-bypass or remote-code-execution classes.
  • Next.js’s two Critical entries are a middleware authorization bypass at CVSS 9.1, disclosed March 21, 2025, and a React Server Components remote code execution scored at 10.0, disclosed December 3, 2025.
  • Adoption does not explain it. Express is installed 130 million times a week, close to three times Next.js’s volume, and carries 5 catalogued vulnerabilities against Next.js’s 66. Nuxt, a comparably scoped meta-framework, sits between them at 22.
  • Vercel shipped 13 advisories in a coordinated release in May 2026, then formalized a scheduled monthly cadence, with the first scheduled release patching 9 more in July. That reflects real surface area and a mature disclosure process at the same time.
  • The argument here is architectural rather than a verdict on engineering quality. A framework that owns more subsystems has more places for something to go wrong, whether that is a cache growing unbounded or an authorization check that a spoofed header can skip.

The numbers, same source, same day

Both counts come from the same database on the same date, which makes them about as directly comparable as vulnerability data gets. Every advisory ever catalogued against the package is included, across all versions and all time, so the totals cover issues patched years ago alongside current ones. Neither package has a known vulnerability affecting its latest release.

Severity is where the comparison sharpens. Next.js’s 64 break down as 2 Critical, 26 High, 28 Moderate, and 8 Low, putting 28 of 64 at High or Critical. Express’s 5 consist of 3 Moderate and 2 Low, and the ceiling is CVE-2024-29041, an open redirect through malformed URLs at CVSS 6.1. Volume alone would be a meaningful difference. The severity distribution makes it a different kind of difference.

Does scope explain the gap?

Partly, and the honest answer matters more than a tidy one. Express is a routing and middleware library. Next.js is a meta-framework with a bundler, an image pipeline, a rendering engine, and a component serialization protocol. More owned code means more places for a bug to live, which is the argument rather than an objection to it.

A same-category comparison shows where scope stops explaining things.

PackageCatalogued vulnerabilitiesWeekly downloadsScope
Express5130.0MRouting and middleware library
Nuxt221.7MFull meta-framework: bundler, SSR, hydration (Vue)
Next.js6644.4MFull meta-framework: bundler, SSR, hydration, RSC

All three rows come from Snyk’s package database rather than OSV, so they sit on a slightly different methodology from the headline count. Snyk and OSV agree on Express at 5.

Nuxt’s 22 lands roughly four times above Express and three times below Next.js, which is where a scope-driven explanation would predict it. The remaining distance between Nuxt and Next.js has a plainer explanation than architecture: Next.js pulls 44.4 million weekly downloads to Nuxt’s 1.7 million, and adoption drives the security research attention that finds vulnerabilities. Anyone treating a raw count as a quality signal is reading it wrong.

That explanation runs out at Express. Express is installed 130 million times a week, close to three times Next.js’s volume, and carries 5 catalogued vulnerabilities against Next.js’s 66. Whatever scrutiny follows adoption, Express attracts more of it and has less to show for it. Scope is the variable left standing.

The two Critical entries

CVE-2025-29927 is a middleware authorization bypass that let an attacker skip authentication and access-control checks by spoofing a single internal HTTP header. The GitHub Security Advisory records a CVSS score of 9.1 and an EPSS score of 92.118%, placing the modeled probability of exploitation within 30 days close to certain. That advisory also notes that “Next.js deployments hosted on Vercel are automatically protected against this vulnerability.” Self-hosted deployments carried the exposure, the same self-hosted-versus-managed divide covered in the memory leak case study.

CVE-2025-55182, nicknamed React2Shell, is an unauthenticated remote code execution flaw in how React Server Components deserialize data sent from client to server. Attribution matters here: the advisory is published against React’s react-server-dom-webpackreact-server-dom-parcel, and react-server-dom-turbopack packages, not against Next.js. It carries a CVSS score of 10.0, the maximum possible, and an EPSS score of 99.562%. Next.js App Router applications inherit it through a downstream advisory, CVE-2025-66478, which Vercel published alongside React’s own disclosure.

The distinction is worth holding onto, and it is not a one-off. The flaw originates upstream in React, and it reaches Next.js because the App Router ships React Server Components by default. The May 2026 release repeated the pattern with a second upstream React advisory. Wiz Research documented that an application built with create-next-app and deployed on default settings was vulnerable with no code changes required, and that multiple independent security teams observed exploitation in the wild, including post-exploitation activity involving cloud credential theft and cryptocurrency mining. A framework that adopts a serialization protocol adopts that protocol’s failure modes.

A monthly release cadence

On May 7, 2026, Vercel shipped a coordinated release patching 13 advisories in Next.js 15.5.18 and 16.2.6. The breakdown is where it gets informative, because the categories track subsystems rather than variations on a single bug.

CategoryAdvisoriesSubsystem
Middleware and proxy bypass5Routing and authorization
Denial of service3Rendering and image pipeline
Cache poisoning2Caching layer
Cross-site scripting2Script handling and CSP
Server-side request forgery1Server-side fetch handling

Two details from that release matter more than the counts. The denial of service entry in React Server Components was tracked upstream as CVE-2026-23870, making it the second time in six months that a headline Next.js advisory originated in React rather than in Next.js itself. And Vercel noted that it deployed no new firewall rules for the release, because these particular advisories cannot be reliably blocked at that layer. Managed hosting absorbed the middleware bypass in 2025; it could not absorb these.

Vercel formalized the process afterward, moving to preannounced, scheduled releases so teams can plan upgrades rather than react to them. The first scheduled release landed July 20, 2026, patching 9 more advisories, 4 High and 5 Medium, in 15.5.21 and 16.2.11.

Those 9 account for the entire movement in the headline count over the past three weeks. A snapshot taken July 18 would have shown 55.

Shipping advisories in batches, each with a CVSS and EPSS score attached and a publication date announced in advance, is what a mature disclosure process looks like. The volume reflects surface area rather than a slow or evasive response to it.

One pattern in the fuller list is harder to read charitably. Fixes have twice needed a follow-up advisory after the first patch proved incomplete: CVE-2026-45109 revisited a segment-prefetch middleware bypass, and CVE-2025-67779 revisited a Server Components denial of service. Getting a fix right the first time is harder when the surface being patched is large and interconnected.

What Express carries

Express’s 5 catalogued vulnerabilities are unremarkable by comparison: a resource injection issue, a missing charset header, an open redirect in malformed URLs, a second open redirect, and reflected cross-site scripting through response.redirect(). Nothing above Moderate, nothing involving authorization bypass or remote code execution, and several dating back a decade.

That reflects surface area rather than superior engineering. A bundler, an image optimization pipeline, a server-side rendering engine, and a component serialization protocol are things Express never has to get right, because it was never asked to own them.

Why this happens, architecturally

The same argument made about memory earlier in this series applies to a different failure mode. A framework that owns a bundler, an image pipeline, a caching layer, an RSC serialization format, and a middleware execution model has more places for something to break. Express has no middleware-bypass vulnerability class, and the reason is that its middleware model is a thin, well-understood primitive with a small space of things that can go wrong inside it.

The categories track architecture rather than any one team’s standards. In January 2026 the Svelte team disclosed five vulnerabilities across Svelte, SvelteKit, its Node adapter, and its serialization library, covering memory and CPU exhaustion during deserialization, a server crash, server-side request forgery, and cross-site scripting through improperly escaped server-rendered markup. A separate codebase built by a separate team on a different rendering model produced the same categories of failure that fill Next.js’s advisory history.

Vulnerability count and severity are one input among several, alongside team familiarity, feature requirements, and how quickly an organization can apply a patch once it ships. For a content-driven site that never needed a component-tree rendering model, the smaller surface was worth more than the features sitting on top of it.

Related reading

The memory leak case study makes the same architectural argument about memory rather than security, and about the same self-hosted-versus-Vercel divide. The full migration writeup covers where this fits among the other reasons for moving off Next.js.

On the broader question of how much a framework still buys, the case for vanilla JavaScript covers what the platform now handles natively, what Node.js gained covers the runtime side, and what React gave back covers the features that flowed from React into the language itself.

RSS Feed Newsletter
Contact us

Latest Blog Posts