AppScan
For Next.js apps

Middleware is not a guard. Find out what is.

Next.js puts authentication in middleware, secrets behind a NEXT_PUBLIC_ prefix, and the server in the same folder as the client. Each of those is a place a rule knows to look - and a place a generic scanner does not.

01The situation

Sound familiar?

Middleware as the only guard

CVE-2025-29927 let one request header skip middleware entirely. If that is where your authentication lives, every route it protected was open.

NEXT_PUBLIC_ means public

The prefix ships a value to every visitor. A key pasted behind it "to make it work" is now in the bundle, and in every cache of it.

Server Actions are routes too

A function marked "use server" is reachable without the page that calls it. It needs the same session check as an API route, and rarely has one.

The bundle tells the story

A production build that publishes source maps hands over the code; a CSP that allows inline scripts hands over the page.

02What changes

Read the way Next.js is actually built.

Route handlers under app/, API routes under pages/, middleware and the public env prefix are recognised as what they are. Rules about the server run on the server half; rules about exposure run on what reaches the browser.

  • The middleware advisory, only if you have middleware

    Next.js middleware can be skipped with one request header is raised when the lockfile version is affected and a middleware file exists - and resolves when either stops being true. source.framework.conditioned-advisory

  • Keys that should have stayed on the server

    A private key behind NEXT_PUBLIC_, VITE_, REACT_APP_ or EXPO_PUBLIC_ is a finding in source, and the invariant that no private key reaches the browser is re-checked on every push. source.secrets.private-key-exposed-to-browser

  • Route handlers found in source

    Both router conventions are detected, so a mutating handler with no session check before its query is named, with the file and the line. source.authorization.unguarded-mutating-route

  • The page as a visitor loads it

    Published source maps, a permissive CSP, render-blocking scripts and Core Web Vitals - measured on a real load, on the free scan. runtime.javascript.source-map-exposed

pnpm-lock.yaml · advisoriesre-evaluated daily
/next@15.1.0:
resolution: {integrity: sha512-…}
Criticalsource.framework.conditioned-advisory
Next.js middleware can be skipped with one request header (CVE-2025-29927)

next 15.1.0 is in the affected range and the application has a middleware file.

not raised CVE-2024-47831 (image optimizer): the app does not use next/image.
03A week with it

What the first week looks like

  1. 01
    Scan the deployed site

    A URL and an email. The report lists what the bundle exposes, what the headers allow and how the page loads.

  2. 02
    Connect the repository

    The inventory reads the lockfile, finds the middleware file and every route handler, and derives the invariants.

  3. 03
    Push

    The next push is classified and checked. A guard removed from a route handler is raised on its own.

  4. 04
    The day an advisory lands

    Your lockfile is already known. If the version is affected and the feature is in use, the finding is on the site that morning.

Where to start
Pro$29 / month

One site, watched continuously, with the repository connected: the lockfile for advisories, the routes for guards, the pushes for regressions.

  • One site with its repository connected
  • All 249 rules, including the 52 source rules
  • Advisories re-evaluated daily, conditioned on the feature
  • Fix with AI as a draft pull request
Create a free account

Start on Free, which does not expire. Upgrade when it pays for itself.

Find out what your Next.js app shipped.

The free scan reads the deployed site. Connecting the repository reads the rest.