Secure Next.js middleware.ts template
Copy-paste Next.js middleware that enforces auth on protected routes, blocks CVE-2025-29927, adds security headers, and handles rate limiting.
How to use
Drop into /middleware.ts. Adjust PROTECTED_PATHS and Ratelimit config to your needs.
Template (tsx)
copy-paste, replace {{PLACEHOLDERS}}import { NextResponse, type NextRequest } from "next/server";
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
// Routes that require authentication
const PROTECTED_PATHS = ["/app", "/api/private"];
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(60, "1 m"),
});
export async function middleware(req: NextRequest) {
// Block CVE-2025-29927 — reject any incoming x-middleware-subrequest header
if (req.headers.has("x-middleware-subrequest")) {
return new NextResponse("rejected", { status: 400 });
}
const { pathname } = req.nextUrl;
// Rate limit all API routes
if (pathname.startsWith("/api/")) {
const ip = req.headers.get("x-forwarded-for")?.split(",")[0] ?? "anon";
const { success } = await ratelimit.limit(ip);
if (!success) return new NextResponse("slow down", { status: 429 });
}
// Enforce auth on protected paths
if (PROTECTED_PATHS.some((p) => pathname.startsWith(p))) {
const session = req.cookies.get("session");
if (!session) {
const url = new URL("/signin", req.url);
url.searchParams.set("redirect", pathname);
return NextResponse.redirect(url);
}
}
return NextResponse.next();
}
export const config = {
matcher: [
"/((?!_next/static|_next/image|favicon.ico|.well-known/).*)",
],
};