Fix guide · low · exposed_nextjs_build_manifest

Next.js _buildManifest.js exposed

What this rule means

Your _next/static/chunks/_buildManifest.js is reachable. The file lists every route in your Next.js build, including admin routes and dynamic-segment routes attackers can probe for IDOR.

Why it matters

Next.js writes a build manifest to _next/static/chunks/_buildManifest.js that lists every route the build produced. It looks like:

self.__BUILD_MANIFEST = (function() {
  return {
    "/": ["static/chunks/pages/index-abc.js"],
    "/admin/dashboard": ["static/chunks/pages/admin/dashboard-def.js"],
    "/admin/users/[id]": ["static/chunks/pages/admin/users/[id]-ghi.js"],
    "/api/internal/health": [],
    ...
  };
}());

The file is loaded by the browser at runtime to enable client-side route prefetching — it's INTENDED to be public. But the route list is also a complete map of:

Next.js makes this file public by design. The risk it surfaces is route-level authorisation — for every route in this list, does your app authenticate the user and check their permissions? If a route is in the manifest, an unauthenticated attacker can hit it and watch for behavioural differences.

How to fix it

  1. Audit the route list. Open _buildManifest.js (in your build output or via the public URL) and treat every listed route as a target. For each:
  1. You can't hide the manifest. It's required for Next.js client-side routing. The defence is making sure every listed route is itself secure.
  2. For routes that ARE admin-only, ensure they redirect unauthenticated users to login and authenticated-but-unauthorised users to a 403. Don't return 404 — leaking presence is exactly the reconnaissance you're trying to avoid.
  3. Consider hash-based admin paths for routes that should be discoverable only by team members (e.g. /admin-abc123def/) — but treat this as defence-in-depth, NOT as the only protection.

Did vibecheck flag this on your app?

If you reached this page from a vibecheck inspection report, the redacted match in your scan output is the exact string we found in your bundle. After applying the fix above, run the inspection again — the finding should clear.

Run another inspection