How to Fix Insecure Rate Limiting in Vibe-Coded Apps
OverMCP Team
Quick answer
Rate limiting is a critical security control that prevents brute-force attacks, credential stuffing, and API abuse by limiting how many requests a user can make in a given time window. Vibe-coded apps often skip it because AI assistants rarely add it unless explicitly asked. To fix insecure rate limiting, you need to add a middleware or library that tracks requests per user or IP, and returns a 429 status when limits are exceeded.
What to check first
Before implementing rate limiting, check if your app already has some form of it:
express-rate-limit; if Next.js, check for middleware or API route handlers that count requests.grep -r "rateLimit\|rate-limit\|throttle" to see if any library or custom code exists.Step-by-step fix
1. Choose a rate limiting strategy
There are two common approaches:
2. Implement in Next.js (App Router)
If you're using Next.js with API routes, you can add rate limiting in a middleware or inside each route handler. Here's a simple in-memory rate limiter for a single-instance app:
// middleware.js
import { NextResponse } from 'next/server'
const rateLimit = new Map()
const WINDOW_MS = 60 * 1000 // 1 minute
const MAX_REQUESTS = 100
export function middleware(request) {
const ip = request.ip ?? 'anonymous'
const now = Date.now()
const entry = rateLimit.get(ip)
if (!entry || now - entry.start > WINDOW_MS) {
rateLimit.set(ip, { start: now, count: 1 })
return NextResponse.next()
}
entry.count += 1
if (entry.count > MAX_REQUESTS) {
return new NextResponse('Too Many Requests', { status: 429 })
}
return NextResponse.next()
}
export const config = {
matcher: '/api/:path*',
}For production with multiple instances, use Redis:
// lib/rateLimit.js
import { Redis } from '@upstash/redis'
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL,
token: process.env.UPSTASH_REDIS_REST_TOKEN,
})
export async function rateLimit(identifier, limit, windowSeconds) {
const key = `rate_limit:${identifier}`
const current = await redis.incr(key)
if (current === 1) {
await redis.expire(key, windowSeconds)
}
return current <= limit
}Then use it in your API route:
// app/api/login/route.js
import { rateLimit } from '@/lib/rateLimit'
export async function POST(request) {
const ip = request.headers.get('x-forwarded-for')?.split(',')[0] ?? 'anonymous'
const allowed = await rateLimit(`login:${ip}`, 5, 60) // 5 requests per minute
if (!allowed) {
return Response.json({ error: 'Too many requests' }, { status: 429 })
}
// handle login
}3. Apply rate limiting to sensitive routes
Focus on routes that are vulnerable to brute-force attacks:
4. Return proper headers
Include X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After headers so clients know when they can retry.
5. Test your implementation
Use a tool like ab or Postman to send many requests and verify you get 429 responses.
Common mistakes
FAQ
How do I choose the right rate limit numbers?
Start with your legitimate user's behavior. If your API is for a single user, 100 requests per minute is fine. For public APIs, consider 60-100 per minute per IP. For login, 5 attempts per minute is standard. Monitor your logs and adjust.
Can I use a third-party service like Cloudflare?
Yes, but if your app is behind a reverse proxy, ensure you trust the X-Forwarded-For header. Otherwise, you can use services like Cloudflare, but for many indie apps, a simple in-app rate limiter is sufficient.
My app is built with Cursor, how do I know if it already has rate limiting?
Search for rateLimit, express-rate-limit, limiter, or throttle in your codebase. If you don't find any, you likely don't have it. Also check your API routes for any conditional that checks request count.
---
You can use our [free AI app security scanner](https://www.overmcp.com/) to detect missing rate limiting and other vulnerabilities in your vibe-coded app. Also check your [security headers](https://www.overmcp.com/tools/headers) and [SSL certificate](https://www.overmcp.com/tools/ssl) to ensure basic security is in place. If you deploy on Vercel, our [Vercel security scanner](https://www.overmcp.com/connect/vercel) can help you continuously monitor your app. For ongoing protection, consider [continuous security monitoring](https://www.overmcp.com/monitor) to catch issues early.