On March 21st, 2025, Next.js disclosed a 9.1 critical vulnerability (CVE) that would allow attackers to bypass middleware-based authorization checks. This issue was originally discovered and investigated by Rachid Allam (zhero) who authored a detailed research paper to outline the specifics.

What is Next.js Middleware

Next.js middleware is a feature that runs code before request completion, allowing developers to modify responses by rewriting, redirecting, changing headers, or responding directly. Next.js middleware is a powerful tool that enables teams to do a lot but the main use cases are:

  • Path rewriting: Dynamically change requested paths
  • Server-side redirects: Easily reroute users based on specific conditions
  • Included response headers: Headers that could be introduce are Content Security Policy (CSP)
  • Authentication and authorization checks: Confirming user identity and checking session cookies before access to specific pages or API routes are granted

Common pattern: Protecting routes by intercepting requests to check session cookies and permissions before granting access (e.g., for /dashboard/admin), forwarding valid requests or redirecting unauthorized users to login.

What is CVE-2025-29927

The CVE-2025-29927 vulnerability comes from a design flaw in how Next.js handles the x-middleware-subrequest header, which was originally meant to mitigate infinite middleware execution loops internally. The vulnerability lies in the fact that this header check can be exploited. By simply adding the x-middleware-subrequest header with the correct value to a request, an attacker can successfully bypass any middleware-based protection mechanisms.

Which Versions Are Affected

Next.js versions affected:

  • 11.1.4 <= 13.5.6
  • 14.0 < 14.2.25
  • 15.0 < 15.2.3
Applications Hosted on Vercel and Netlify Are Not Impacted

Applications deployed as static exports (where middleware doesn’t execute) are not impacted.

Remediation Actions Teams Should Take

The company behind Next.js, quickly released patches for the vulnerability.

Official Patches:

  • For Next.js 15.x, this issue is fixed in 15.2.3
  • For Next.js 14.x, this issue is fixed in 14.2.25
  • For Next.js 13.x, this issue is fixed in 13.5.9
  • For Next.js 12.x, this issue is fixed in 12.3.5

If patching is infeasible, it is recommended to implement a workaround.

Suggested Workarounds:

A workaround if upgrading to a safe version is infeasible, filtering the x-middleware-subrequest header from requests before they reach the application (case insensitive) is recommended.

Additionally, Cloudflare has released a managed WAF rule, but it's opt-in only because some third-party authentication vendors were failing requests where they use the x-middleware-subrequest header

Miggo Ensures Teams Can Detect and Respond to Next.js Exploits

CVE-2025-29927 is a critical reminder of how implementing details in web frameworks can introduce unintended security vulnerabilities. Miggo was designed to detect and respond to vulnerabilities just like this one. How would Miggo users be equipped to act when an exploit like CVE-2025-29927 is exposed?

  1. Users would start by using an up-to-date and real-time application ecosystem graph to understand how new CVEs potentially impact compromised services.
  2. Then, they would be provided with an accurate risk score built with key factors like: runtime application context (internet facing, sensitive data access, etc.) and function level reachability of the CVE.
  3. Once the noise has been reduced and the finding validated, developers can quickly deploy a patch, with the response guidance provided by Miggo.
Miggo's Vulnerabilties View

Want to learn more about how Miggo can provide you with what’s required to detect and respond to application level exploits? Book time with an expert.

<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/Flip.min.js"></script>

<script>
  document.addEventListener("DOMContentLoaded", (event) => {
    gsap.registerPlugin(Flip);
    const state = Flip.getState("");
    const element = document.querySelector("");
    element.classList.toggle("");
    Flip.from(state, {
      duration: 0,
      ease: "none",
      absolute: true,
    });
  });
</script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/Flip.min.js"></script>

<script>
  document.addEventListener("DOMContentLoaded", (event) => {
    gsap.registerPlugin(Flip);
    const state = Flip.getState("");
    const element = document.querySelector("");
    element.classList.toggle("");
    Flip.from(state, {
      duration: 0,
      ease: "none",
      absolute: true,
    });
  });
</script>