Softechinfra
Development

Next.js Middleware CVE-2025-29927: Fix Steps and Lessons

One spoofed header let attackers walk past Next.js middleware auth. Get the exact patch steps we ran in hours and the defense-in-depth rules that last.

Hrishikesh BaidyaHrishikesh Baidya
March 22, 202510 min read
Next.js Middleware CVE-2025-29927: Fix Steps and Lessons

The Next.js middleware CVE disclosed this week—CVE-2025-29927—is the rare vulnerability that is both trivially simple and genuinely severe. Add one HTTP header, x-middleware-subrequest, with the right value, and affected Next.js applications skip their middleware entirely. No exploit chain, no race condition, no privilege escalation: a single spoofed header, and every authentication redirect, geo-block, and security header your middleware applies simply does not run. It carries a CVSS score of 9.1, and it affects every major Next.js release line going back years. We spent yesterday patching and auditing every Next.js application that Softechinfra's web development team maintains—client projects and in-house products alike. This post documents exactly what we did, in order, so you can run the same playbook. More importantly, it covers the durable lessons, because the specific patch will be ancient history in a year, but the architectural mistake this CVE punishes will keep appearing in new frameworks forever.

What CVE-2025-29927 Actually Does

Next.js middleware runs before a request reaches your route. Teams use it for authentication checks, redirects, security headers like CSP, geo-based routing, and rewrites. Internally, when middleware triggers a subrequest, Next.js marks that subrequest with the x-middleware-subrequest header so the middleware does not run again and recurse forever. That header was the entire trust mechanism—and nothing stopped an external client from sending it.

Security researchers Rachid and Yasser Allam found that an attacker who supplies the header with the correct value (which varies by version but is guessable, since it derives from the middleware file path repeated up to the recursion limit) makes the framework treat the request as already processed. Middleware is skipped. If your only authentication check lived in middleware, every protected route just became public.

Key facts, current as of this writing on March 22, 2025:

  • Affected versions: essentially every release line from 11.1.4 onward, including 12.x, 13.x, 14.x before 14.2.25, and 15.x before 15.2.3.
  • Patched versions: 14.2.25 and 15.2.3. Older major versions did not yet have official backports when we ran our audit, which makes the header-stripping mitigation below essential for legacy apps.
  • Who is most exposed: self-hosted Next.js deployments (Docker, VPS, Kubernetes, next start behind nginx) that rely on middleware for authorization. Some managed hosting platforms announced they strip or neutralize the header at their edge, shielding hosted apps—but verify your provider's statement rather than assuming.
  • Who is least exposed: apps that do not use middleware at all, or that treat middleware as a convenience layer with real authorization enforced deeper in the stack.
  • How the Disclosure Unfolded

    Late Feb 2025

    Private Report

    Researchers responsibly disclose the middleware bypass to the Next.js maintainers.

    Mid-March 2025

    Patches Land

    Fixes ship in Next.js 14.2.25 and 15.2.3, which strip the internal header on external requests.

    March 21, 2025

    Public Disclosure

    CVE-2025-29927 and the researchers' technical write-up go public; CDN and WAF providers begin shipping managed rules.

    March 22, 2025

    Industry Response

    Teams everywhere—ours included—patch, verify, and audit what middleware was silently responsible for.

    The Response Playbook We Ran

    Here is the sequence we followed across every Next.js codebase we maintain. It took a few hours per application, and most of that time was verification, not patching.

    1
    Inventory Every Next.js App and Its Middleware
    List every deployment, its exact Next.js version, and whether a middleware file exists. Then answer the only question that matters: does middleware make security decisions here—auth redirects, role checks, geo-blocks, CSP—or only cosmetic ones? Severity depends entirely on this answer.
    2
    Patch or Mitigate, Same Day
    Upgrade to 14.2.25 or 15.2.3 where possible. For apps stuck on older lines, configure the reverse proxy, load balancer, or WAF to strip or reject any inbound request carrying the x-middleware-subrequest header. A legitimate external client never sends it, so dropping it breaks nothing.
    3
    Verify the Bypass Is Actually Closed
    Do not trust the version bump. Send a request to a protected route with the spoofed header and confirm you still get redirected or rejected. Our QA lead Manvi added this exact probe to our regression suite, against staging and production, for every app—a five-minute test that converts an assumption into evidence.
    4
    Audit Everything Middleware Was Solely Responsible For
    The patch closes the hole; the audit tells you what was behind it. For each middleware responsibility—session checks, admin gating, security headers, rate-limit hints—ask whether any deeper layer would have caught an unauthorized request. Where the answer was no, that is your real finding.
    5
    Add Detection
    Log and alert on any external request that arrives with internal framework headers. Attackers scan for this CVE in bulk now that it is public; an alert tells you who is probing and whether anyone probed before you patched. Check historical access logs for the header while you are at it.

    When we ran step 4 across our own products, the audit was reassuring but still instructive. ExamReady, our exam-preparation platform, uses middleware for convenience redirects, but every API route and data query re-validates the session server-side—so a middleware bypass would have produced broken redirects, not data exposure. The same layered pattern protects TalkDrill, our in-house English-speaking practice app, where session and entitlement checks sit in the backend services rather than in any front-layer gate. That is not luck; it is a standard we enforce in code review, and this week it paid for itself.

    The Durable Lesson: Middleware Is Not a Security Boundary

    "A framework feature can be a convenience layer or a security boundary—rarely both by default. CVE-2025-29927 punished every team that treated Next.js middleware as a boundary while the framework treated it as a convenience. The fix is not a version bump; it is refusing to let any single layer be the only thing between an attacker and your data."
    HB
    Hrishikesh Baidya CTO, Softechinfra

    Middleware-only auth was always fragile, and not only because of this CVE. Middleware in Next.js runs in a constrained runtime, often cannot reach your database cheaply, and encourages optimistic checks—reading a cookie and trusting it—rather than authoritative ones. The official guidance has long leaned the same way: use middleware for optimistic redirects, and enforce authorization where the data lives.

    Here is the layered model we apply on every project, whatever the framework:

    Layer 1: Edge and Middleware — UX, Not Enforcement

    Redirect logged-out users to the login page, apply locale routing, set security headers. Treat all of it as user experience. If this layer silently disappeared—exactly what this CVE made happen—nothing confidential should become reachable.

    Layer 2: Route and Server-Side Checks

    Every server-rendered page, API route, and server action that touches protected resources verifies the session itself. This feels redundant. It is redundant. Redundancy is the entire point of defense in depth: the second check exists precisely for the day the first one fails.

    Layer 3: The Data Access Layer — the Authoritative Gate

    Centralize data access in functions that take the authenticated user as an input and refuse to return rows that user cannot see. When authorization lives next to the query, a bypassed front layer yields an empty page instead of someone else's records. This is the single highest-leverage refactor for most codebases we inherit, and a core theme of our secure software development guide.

    Layer 4: Database Constraints

    Row-level security, separate credentials for separate services, and least-privilege grants mean that even an application-level failure has a blast radius measured in one user's data, not the whole table.

    Never Trust Internal Headers From the Outside

    The second evergreen lesson generalizes far beyond Next.js. Frameworks, proxies, and meshes all communicate with themselves through headers: x-middleware-subrequest, x-forwarded-for, assorted x-internal-* conventions. Any header that encodes a trust decision must be stripped or overwritten at your outermost boundary, because an attacker can type anything into an HTTP request. We have seen the same class of bug enable rate-limit evasion through spoofed client IPs—covered in our rate limiting guide—and admin-panel exposure through a forged internal-service header. Make "strip unknown and internal headers at the edge" a standing rule in your gateway or proxy configuration, then it protects you from vulnerabilities that have not been discovered yet.

    Build the Patch Muscle Before You Need It

    The teams that handled this week well were not the ones with the cleverest middleware; they were the ones who could ship a dependency upgrade to production within hours, confidently. That capability is built in advance:

  • Maintain a live inventory of frameworks and versions per deployment. If "which apps run Next.js 13?" takes a meeting to answer, your response time is measured in days.
  • Subscribe to advisories for your core stack—GitHub security advisories and your framework's release channel—so disclosure reaches you on day one, not via a client's panicked email.
  • Set severity-based SLAs: critical authentication bypasses get same-day mitigation, highs get 48 hours. Decide this before an incident, when nobody is stressed.
  • Keep upgrade paths short. Teams several majors behind faced an ugly choice this week: a risky big-bang upgrade or proxy mitigations on a frozen codebase. Staying within one major of current is cheap insurance, an argument our founder Vivek Kumar has been making to clients since long before this CVE, and one Vivek Kumar bakes into every maintenance contract we sign.
  • Automate the boring proof. A CI test that requests a protected route unauthenticated—with and without suspicious headers—turns "we think auth works" into "auth is asserted on every deploy."
  • What to Do Monday Morning

    If you run Next.js anywhere, the version-specific work is clear: confirm you are on 14.2.25 or 15.2.3 (or that your edge strips the header), prove it with a spoofed-header probe, and search your logs for historical abuse. If you are reading this long after March 2025, the patch is settled history—so run the evergreen audit instead. Find every place where exactly one check stands between the public internet and private data, and add a second, deeper one. CVE-2025-29927 will not be the last time a framework's front gate swings open; defense in depth is what determines whether that headline is an incident for you or just a changelog entry.

    Worried About What a Single Bypassed Layer Would Expose?

    We run security-focused audits of Next.js and full-stack applications—patch response, auth architecture reviews, and the layered hardening that makes the next CVE a non-event.

    Request a Security Review
    Tags:
    next.js securitycve-2025-29927middleware auth bypassdefense in depthweb application securityvulnerability responsepatch management
    Share this post:
    Hrishikesh Baidya

    Hrishikesh Baidya

    CTO at Softechinfra specializing in Python, system architecture, and building secure, scalable software solutions.