Authorization belongs beside the data it protects
Next.js middleware can reject requests early. Sensitive reads and writes still need mandatory authorization, with policy ownership clear at every entry point.
An invoice download should decide whether the caller may read that invoice even when the request has already passed a route check. The March 2025 Next.js middleware bypass made this separation urgent: early rejection is useful, but sensitive reads and writes need mandatory authorization at the boundary that performs the operation. Otherwise a routing assumption can become the only protection between customers' records.
Looking back from November 2026, the advisory published on 21 March 2025 describes authorization bypass when checks occur in middleware. Its affected ranges are ≥11.1.4 and <12.3.5; ≥13.0.0 and <13.5.9; ≥14.0 and <14.2.25; and ≥15.0 and <15.2.3. The corresponding fixes are 12.3.5, 13.5.9, 14.2.25 and 15.2.3. These identify historical repairs, not suitable upgrade targets for every application today.
Reject early, decide at the operation
Middleware can keep an anonymous visitor away from an account page before the application spends effort rendering it. That improves navigation and reduces unnecessary work. It does not establish which account's invoices a recognized user may download. A route can be private while a record selected inside it belongs to someone else.
Consider an illustrative portal with a page, a download endpoint and a background export. All three can reach the same invoice data. If the permission check exists only on the page route, the other callers inherit an undocumented assumption. The proposed design should make the protected operation demand trusted caller context and verify permission for the requested invoice before returning its contents.
The same principle applies to changing a payment instruction. Recognizing an employee is one input. Their current authority to change this instruction is another. A generic “signed in” condition cannot express that distinction. The operation needs the relevant action and resource, with customer membership derived from trusted application state rather than accepted from a submitted identifier.
This is a recommendation about placement, not an exploit experiment or a guarantee against every access-control defect. The application still needs correct identity validation, correct policies and a maintained framework. Moving an incorrect decision closer to the database does not make it correct.
Repair the defect and inspect the assumption
Vercel's postmortem dated 25 March provides the incident chronology and deployment context. The advisory separately says deployments hosted on Vercel were automatically protected against this vulnerability. That qualification matters: the existence of an affected package version alone does not prove that every hosting arrangement had identical exposure.
A project response should establish the deployed version and hosting path, apply an appropriate maintained fix, and review where sensitive operations obtain their authority. Those are separate questions. A successful framework update addresses the identified defect; it does not demonstrate that an export endpoint correctly distinguishes one customer from another.
For a proposed review, trace a sensitive read from its entry point to the returned record. Identify the caller, the resource and the point that enforces the decision. Repeat that reasoning for a write. Include alternate callers, such as scheduled jobs, whose authority may come from a service identity rather than a browser session. These are suggested checks, not checks performed on an AL+ client application.
The business consequence is responsibility after the patch. If the only description is “middleware handles security,” a future export or integration can bypass the intended policy accidentally. An operation-level contract gives its author a concrete requirement that survives a change of route or user interface.
Central policy can still avoid duplication
The strongest objection is that repeating authorization throughout the application creates inconsistent rules. That objection is valid when every endpoint invents its own interpretation of membership and ownership. Mandatory enforcement does not require independent policy implementations. A shared policy module or central policy service can answer the same question for several callers.
The distinction is between deciding the rule and enforcing its result. A central service might evaluate whether an identified employee may approve a particular payment. Each protected operation still needs to require that decision before acting. A caller should not be able to omit the check simply because another route usually performs it first.
Centralization brings operating choices. If the policy service is unavailable, a sensitive operation needs a defined failure behavior. Cached decisions need an explicit lifetime and a response to revoked authority. These are design questions to settle for the proposed system, not evidence that a separate policy service is necessary for a small portal.
For a compact application, a well-defined local function may be easier to inspect and maintain. A separate service becomes attractive when several independently deployed systems genuinely share policy ownership. Introducing network calls merely to obtain architectural uniformity can add failure paths without improving the rule itself.
Leave the next maintainer a usable boundary
This issue differs from choosing sessions over signed tokens or making login the default across private pages. Those choices concern identity lifecycle and route policy. Here the requirement is that every path to a sensitive operation encounters its authorization decision, with enough context to distinguish the requested action and record.
For custom software development, ask for a short map connecting important reads and writes to their enforcement points. Keep early middleware rejection where it helps. Make the operation's authority independently reviewable, and document any central policy dependency. The useful outcome is a maintainer who can add a new caller without guessing where permission was supposed to have been checked.
Paul