TL;DR
- Three High-severity issues in Next.js allow middleware/proxy checks to be bypassed in certain routing scenarios.
- Affected Next.js versions: 12.2.0–15.5.15 (Pages Router with i18n), 15.2.0–15.5.15 (App Router via segment-prefetch), and 15.4.0–15.5.15 (dynamic route param injection).
- Upgrade Next.js to exactly 15.5.16 to remediate.
- Your next scheduled FrameScan run already checks for these CVEs.
At-a-glance
| ID | Impact | Severity | Affected versions | Fixed version |
|---|---|---|---|---|
| CVE-2026-44573 | Requests can skip middleware in Pages Router i18n flows | high | >=12.2.0,<15.5.16 | 15.5.16 |
| CVE-2026-44574 | Dynamic route param tricks can bypass middleware/proxy | high | >=15.4.0,<15.5.16 | 15.5.16 |
| CVE-2026-44575 | App Router segment-prefetch paths bypass protections | high | >=15.2.0,<15.5.16 | 15.5.16 |
CVE-2026-44573 — Next.js Pages Router i18n middleware/proxy bypass
Attackers could reach routes you expect to be gated by middleware or a reverse proxy rule by leveraging i18n routing behavior. This can expose protected pages or internal endpoints. Treat as high priority if you rely on middleware for auth, geo, or IP rules in Pages Router with i18n.
Technical details
Based on the advisory, certain i18n paths in the Pages Router could allow requests to slip past middleware or proxy checks. The safe pattern is to normalize and enforce checks on the canonical pathname and not rely on locale-prefixed variants alone. Ensure the middleware runs for all locale variants and that proxy rules account for i18n prefixes.
Illustrative example — not Next.js source:
Vulnerable pattern (middleware fails to normalize locales and unintentionally skips checks for some locale paths):
// middleware.js (illustrative example)
import { NextResponse } from 'next/server';
export function middleware(req) {
const url = new URL(req.url);
// Only enforce auth on non-prefixed paths; locale-prefixed paths bypass unintentionally
if (!url.pathname.startsWith('/en') && !url.pathname.startsWith('/es')) {
if (!req.headers.get('x-user-authenticated')) {
return NextResponse.redirect(new URL('/login', url));
}
}
return NextResponse.next();
}
export const config = {
matcher: ['/((?!_next|api/public).*)'],
};
Fixed pattern (normalize locale and apply the same rule regardless of locale prefix):
// middleware.js (illustrative example — fixed)
import { NextResponse } from 'next/server';
function stripLocale(pathname) {
// Example locales; align with your i18n config
const locales = ['en', 'es', 'fr'];
const parts = pathname.split('/').filter(Boolean);
if (parts.length > 0 && locales.includes(parts[0])) {
return '/' + parts.slice(1).join('/');
}
return pathname;
}
export function middleware(req) {
const url = new URL(req.url);
const canonicalPath = stripLocale(url.pathname) || '/';
const isPublic = canonicalPath.startsWith('/login') || canonicalPath.startsWith('/public');
if (!isPublic && !req.headers.get('x-user-authenticated')) {
return NextResponse.redirect(new URL('/login', url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/((?!_next|api/public).*)'],
};
CVE-2026-44574 — Next.js dynamic route parameter injection bypass
An attacker might craft route parameters to slip past middleware or proxy conditions, potentially reaching endpoints that should require authentication or internal access. Prioritize this if you depend on middleware for route-level access control in dynamic routes.
Technical details
The advisory describes a bypass via dynamic route parameter injection. The robust approach is to validate and normalize parameters before applying access decisions, and to avoid building security decisions from untrusted path segments alone. Use strict matchers and server-side validation.
Illustrative example — not Next.js source:
Vulnerable pattern (auth check keyed off an unvalidated dynamic parameter):
// middleware.js (illustrative example)
import { NextResponse } from 'next/server';
export function middleware(req) {
const url = new URL(req.url);
const segments = url.pathname.split('/').filter(Boolean);
const project = segments[1]; // e.g., /projects/[project]
// Unsafe: treating certain project names as public based on the raw param
const isPublicProject = project === 'public' || project?.startsWith('demo-');
if (!isPublicProject && !req.headers.get('x-user-authenticated')) {
return NextResponse.redirect(new URL('/login', url));
}
return NextResponse.next();
}
Fixed pattern (server-side validation of params and explicit allowlist):
// middleware.js (illustrative example — fixed)
import { NextResponse } from 'next/server';
const PUBLIC_PROJECTS = new Set(['public']);
function isPublicProject(param) {
// Only allow exact, known-safe identifiers
return PUBLIC_PROJECTS.has(param);
}
export function middleware(req) {
const url = new URL(req.url);
const parts = url.pathname.split('/').filter(Boolean);
const project = parts[1] || '';
const isPublic = isPublicProject(project) || url.pathname.startsWith('/login');
if (!isPublic && !req.headers.get('x-user-authenticated')) {
return NextResponse.redirect(new URL('/login', url));
}
return NextResponse.next();
}
CVE-2026-44575 — Next.js App Router segment-prefetch bypass
Requests using segment-prefetch routes in the App Router could avoid middleware or proxy protections, opening a path to resources you intended to protect. If you rely on App Router middleware for auth or request filtering, treat this as high urgency.
Technical details
Per the advisory, certain segment-prefetch routes can cause middleware/proxy to be skipped. A safer pattern is to avoid treating any prefetch-style path or hint as inherently safe; perform the same checks regardless of request source and ensure your matcher includes the relevant patterns.
Illustrative example — not Next.js source:
Vulnerable pattern (skipping checks for suspected prefetch requests):
// middleware.js (illustrative example)
import { NextResponse } from 'next/server';
export function middleware(req) {
const url = new URL(req.url);
// Incorrectly trust prefetch-like paths or hints
if (url.searchParams.get('prefetch') === '1') {
return NextResponse.next();
}
if (!req.headers.get('x-user-authenticated')) {
return NextResponse.redirect(new URL('/login', url));
}
return NextResponse.next();
}
Fixed pattern (apply auth consistently, regardless of prefetch indicators):
// middleware.js (illustrative example — fixed)
import { NextResponse } from 'next/server';
export function middleware(req) {
const url = new URL(req.url);
const isPublic = url.pathname.startsWith('/login') || url.pathname.startsWith('/assets');
if (!isPublic && !req.headers.get('x-user-authenticated')) {
return NextResponse.redirect(new URL('/login', url));
}
return NextResponse.next();
}
export const config = {
// Ensure matchers include prefetch-related paths as applicable to your app
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};
Remediation
- Upgrade Next.js to 15.5.16.
- npm:
npm install next@15.5.16 - yarn:
yarn add next@15.5.16 - pnpm:
pnpm add next@15.5.16 - Review the official advisories for details and any additional guidance:
- CVE-2026-44573: https://github.com/vercel/next.js/security/advisories/GHSA-36qx-fr4f-26g5
- CVE-2026-44574: https://github.com/vercel/next.js/security/advisories/GHSA-492v-c6pp-mqqv
- CVE-2026-44575: https://github.com/vercel/next.js/security/advisories/GHSA-267c-6grr-h53f
Call to action
- Existing customers: run a scan now at https://framescan.io/scan
- New here? Your first scan per verified domain is free: https://framescan.io/#pricing