Fix Missing Rate Limiting in AI-Coded Apps: A Practical Guide
OverMCP Team
Quick answer
Rate limiting controls how many requests a user or IP can make to your app in a given time. Many AI-coded apps skip it entirely, making them easy targets for brute-force attacks, API abuse, and denial-of-service. To fix missing rate limiting, add a middleware or library to your backend that tracks requests and returns 429 status when limits are exceeded.
What is rate limiting and why vibe-coded apps miss it
When you use tools like Cursor, Bolt.new, or v0 to generate an app quickly, the AI focuses on core functionality—authentication, database queries, UI components. Rate limiting is an "invisible" security measure that often gets left out because:
But without rate limiting, a single user can hammer your login endpoint thousands of times per minute, guess passwords, or drain your API credits. This is especially dangerous for indie makers running on free tiers—one bad actor can cost you real money.
What to check first
Before writing code, audit your app for rate limiting gaps:
express-rate-limit, @nestjs/throttler)?If you answered "no" to any of these, your app likely has missing rate limiting.
Step-by-step fix
Here's how to add rate limiting to a Node.js/Express app generated by AI. The same pattern applies to other frameworks.
1. Install a rate limiting library
npm install express-rate-limit2. Create a rate limiter middleware
In your server file (e.g., app.js or server.js), import and configure the limiter:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // limit each IP to 100 requests per windowMs
standardHeaders: true,
legacyHeaders: false,
message: { error: 'Too many requests, please try again later.' }
});
// Apply to all routes
app.use(limiter);3. Apply stricter limits to sensitive endpoints
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // 5 login attempts per 15 minutes
message: { error: 'Too many login attempts. Try again later.' }
});
app.post('/api/login', authLimiter, (req, res) => {
// login logic
});4. Test your implementation
Use curl or a tool like OverMCP's free security scanner to verify that repeated requests receive a 429 status.
for i in {1..10}; do curl -X POST http://localhost:3000/api/login -d '{"username":"test","password":"wrong"}' -H "Content-Type: application/json"; done5. For serverless environments (Vercel, Netlify)
If you're deploying on Vercel, you can use the @vercel/rate-limiter helper or implement a custom middleware with Upstash or Redis. For a quick fix, add the express-rate-limit approach inside your API route files—but note that serverless functions are stateless, so you'll need an external store like Redis for accurate counts.
// Example using Upstash Redis for serverless
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s'),
});
export default async function handler(req, res) {
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
const { success } = await ratelimit.limit(ip);
if (!success) return res.status(429).json({ error: 'Too fast' });
// ... rest of handler
}Common mistakes
Even when developers add rate limiting, they often make these errors:
1. Only limiting by IP
Attackers can rotate IPs using VPNs or botnets. Combine IP with user ID or session tokens for better accuracy. Use a tool like OverMCP's continuous security monitoring to detect abuse patterns in real time.
2. Setting limits too high or too low
3. Forgetting to limit error responses
If your login endpoint returns a 429 after 5 attempts, but your password reset endpoint has no limit, attackers will pivot there. Apply rate limiting to all authentication endpoints.
4. Not returning proper headers
Standard rate limit headers (X-RateLimit-Limit, X-RateLimit-Remaining) help clients back off gracefully. The express-rate-limit library includes them by default.
Why this matters for vibe-coded apps
AI-generated code is often deployed to production faster than traditionally built apps. A missing rate limit can lead to:
By adding rate limiting, you protect your app, your users, and your wallet. OverMCP can help you scan your app for missing rate limiting as part of a broader security audit.
FAQ
How do I know if my vibe-coded app needs rate limiting?
If your app has any public endpoint that accepts user input, especially authentication or paid API endpoints, you need rate limiting. The easiest way to check is to use a free security scanner that tests for rate limiting gaps.
Can I add rate limiting after deployment?
Yes, but it's easier to add it before launch. You can add middleware to your existing app without changing the database or frontend. Just install the library and apply the middleware.
What's the best rate limiting strategy for a solo developer?
Start with IP-based limiting using express-rate-limit or a similar library. As your app grows, move to user-based limits with Redis for serverless environments. OverMCP's continuous monitoring can alert you if your limits are being bypassed.
---
This article is part of a series on securing vibe-coded apps. Check out our [Vercel security scanner](https://www.overmcp.com/connect/vercel) for more deployment-specific checks.