Fix Lack of Resources & Rate Limiting in Next.js
Unprotected endpoints in Next.js are an invitation for resource exhaustion and DoS. Whether you are using App Router or Pages Router, failing to implement rate limiting allows attackers to spam expensive operations—like DB writes, password resets, or heavy computation—resulting in high latency and ballooning compute costs. In a serverless environment, local variables won't cut it; you need a distributed state (Redis) to track request frequency across multiple instances.
The Vulnerable Pattern
export async function POST(req: Request) { const { email } = await req.json();// VULNERABILITY: No check on request frequency. // An attacker can call this 10,000 times a second to exhaust DB connections or email credits. await db.user.resetPassword(email);
return new Response(JSON.stringify({ message: ‘Email sent’ }), { status: 200 }); }
The Secure Implementation
The secure implementation utilizes a 'Sliding Window' algorithm backed by Redis to maintain a global state across serverless function invocations. By identifying the client via IP address (or session token), the middleware intercepts the request before any expensive logic is executed. If the limit is exceeded, it immediately returns a 429 status code. This prevents resource exhaustion at the application and database layers and provides standard headers (X-RateLimit-*) to inform legitimate clients of their quota.
import { Ratelimit } from '@upstash/ratelimit'; import { Redis } from '@upstash/redis';// Initialize distributed rate limiter const ratelimit = new Ratelimit({ redis: Redis.fromEnv(), limiter: Ratelimit.slidingWindow(5, ‘60 s’), // 5 requests per minute analytics: true, });
export async function POST(req: Request) { const ip = req.headers.get(‘x-forwarded-for’) ?? ‘127.0.0.1’;
// Check the bucket const { success, limit, reset, remaining } = await ratelimit.limit(
ratelimit_reset_${ip});if (!success) { return new Response(‘Too Many Requests’, { status: 429, headers: { ‘X-RateLimit-Limit’: limit.toString(), ‘X-RateLimit-Remaining’: remaining.toString(), ‘X-RateLimit-Reset’: reset.toString(), }, }); }
const { email } = await req.json(); await db.user.resetPassword(email);
return new Response(JSON.stringify({ message: ‘Email sent’ }), { status: 200 }); }
Your Next.js API
might be exposed to Lack of Resources & Rate Limiting
74% of Next.js apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.