← All posts
API rate limitingvibe codingsecurityAI coding toolsNode.js

API Rate Limit Bypass: Secure Your Vibe-Coded App

O

OverMCP Team

Quick answer

API rate limit bypass happens when an attacker circumvents your app's request limits by rotating IP addresses, manipulating headers, or exploiting missing authentication checks. To fix it, implement rate limiting on your backend using a sliding window algorithm, always authenticate requests before applying limits, and use a centralized store like Redis for distributed apps.

Why vibe-coded apps are vulnerable to rate limit bypass

When you build an app fast with AI coding tools, the generated code often includes a simple rate limiter—if any at all. You might get a middleware that counts requests per IP in a local object, which works fine on your local machine. But once deployed, that in-memory store resets on every server restart or fails across multiple instances. Worse, the limiter might only check IP addresses, which attackers can easily spoof via the X-Forwarded-For header. This is one of the most common API rate limit bypass vulnerabilities in AI-built apps.

What to check first

Before diving into fixes, audit your current implementation with this checklist:

  • [ ] Is rate limiting applied to all public API endpoints (especially login, signup, and data-fetching routes)?
  • [ ] Are you using an in-memory store (e.g., a plain object in Node.js) for tracking requests?
  • [ ] Do you rely solely on the client IP address from req.ip or req.connection.remoteAddress?
  • [ ] Have you tested what happens when a user sends a custom X-Forwarded-For header?
  • [ ] Is your rate limiter applied before or after authentication? (Should be after authentication when possible.)
  • [ ] Do you have monitoring to detect unusual traffic patterns?
  • Common mistakes in AI-generated apps

    1. Using local in-memory storage

    Most AI-generated rate limiters use a simple JavaScript object or Map to store request counts. This works in development but resets on server restart and doesn't scale across multiple instances. An attacker can simply wait for a restart or hit different server instances to bypass limits.

    2. Trusting client IP headers blindly

    Many apps read the IP from req.headers['x-forwarded-for'] without validation. Attackers can send a fake header to impersonate other users or reset their own limit. Always use the last IP in the chain (the one added by your proxy) or trust only the direct connection IP.

    3. Not differentiating between authenticated and unauthenticated requests

    If your rate limiter counts all requests before authentication, an attacker can exhaust the global limit and deny service to legitimate users. Apply stricter limits on unauthenticated endpoints and use user IDs for authenticated ones.

    4. Ignoring distributed denial of service (DDoS) via slow loris attacks

    AI-coded apps often miss connection-level rate limiting. An attacker can open many slow connections that stay alive, consuming server resources. Use a reverse proxy like NGINX or a web application firewall (WAF) to cap concurrent connections.

    Step-by-step fix

    Step 1: Choose a centralized store

    Replace local in-memory storage with Redis or a database. For Node.js apps, use express-rate-limit with rate-limit-redis:

    const rateLimit = require('express-rate-limit');
    const RedisStore = require('rate-limit-redis');
    const Redis = require('ioredis');
    
    const redisClient = new Redis(process.env.REDIS_URL);
    
    const limiter = rateLimit({
      store: new RedisStore({
        client: redisClient,
        prefix: 'rate-limit:',
      }),
      windowMs: 15 * 60 * 1000, // 15 minutes
      max: 100, // limit each IP to 100 requests per windowMs
      message: 'Too many requests, please try again later.',
      standardHeaders: true,
      legacyHeaders: false,
    });
    
    app.use('/api/', limiter);

    Step 2: Validate IP headers

    Configure your proxy (e.g., NGINX, Vercel) to set a trusted header. In Express, trust the proxy:

    app.set('trust proxy', 1);

    Then use req.ip which returns the correct IP. If you must parse X-Forwarded-For, take the rightmost IP (the one added by your proxy).

    Step 3: Apply per-user limits after authentication

    Create separate limiters for authenticated and unauthenticated routes:

    const apiLimiter = rateLimit({
      windowMs: 15 * 60 * 1000,
      max: 100,
      keyGenerator: (req) => req.user ? req.user.id : req.ip,
    });
    
    app.use('/api/', apiLimiter);

    For stricter login limits, use a smaller window:

    const loginLimiter = rateLimit({
      windowMs: 15 * 60 * 1000,
      max: 5,
      skipSuccessfulRequests: true,
    });
    
    app.post('/api/login', loginLimiter, loginHandler);

    Step 4: Add connection-level limiting (optional but recommended)

    If you're using NGINX, add:

    limit_conn_zone $binary_remote_addr zone=addr:10m;
    limit_conn addr 10;

    Step 5: Monitor and alert

    Use a service like OverMCP's continuous security monitoring to detect unusual traffic spikes that might indicate a bypass attempt. You can also set up logging for rate limit hits and review them regularly.

    Testing your fix

    Deploy the changes and test with these scenarios:

  • Send 101 requests within 15 minutes from the same IP – expect a 429 status on the 101st.
  • Send requests with a fake X-Forwarded-For header – the limiter should still use the real IP.
  • Log in as a user and send requests – the limit should be per user, not per IP.
  • Deploy to multiple instances and verify the Redis store is shared.
  • How OverMCP helps

    Instead of manually checking each endpoint, you can scan your app for free with OverMCP's security scanner. It will detect missing rate limiting, misconfigured IP trust, and other common vulnerabilities in vibe-coded apps. After fixing, run a security headers check to ensure your app is hardened against other attacks.

    FAQ

    Can API rate limit bypass lead to account takeover?

    Yes, if combined with brute-force attacks on login endpoints without proper per-user rate limiting, an attacker can bypass IP-based limits and guess passwords. Always use per-user limits and account lockout mechanisms.

    Does using a serverless platform like Vercel protect me?

    Vercel provides some DDoS protection at the edge, but application-level rate limiting is still your responsibility. Without it, your API can be abused for scraping or data exfiltration. Use their @vercel/edge rate limiting or implement your own.

    How do I test if my app is vulnerable to rate limit bypass?

    Try sending requests with different X-Forwarded-For values using a tool like curl or Postman. If you see different rate limit responses, you're vulnerable. Also check if the limit resets on server restart or across different regions.

    ---

    By following this guide, you can prevent API rate limit bypass in your vibe-coded app and protect it from abuse. For a full security audit, use OverMCP's free scanner to catch other issues like leaked secrets or missing headers.

    Is your app secure?

    Free scan in 30 seconds. No signup needed.

    Scan My App Free