# Rate limiting implemented

- **Pattern:** `ab-002204` (`saas-api-design.api-security.rate-limiting`)
- **Severity:** critical
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002204
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002204)

## Why it matters

Absent rate limiting on authentication endpoints is one of the most commonly exploited API weaknesses — OWASP API 2023 lists it under both API4 (unrestricted resource consumption) and API7 (authentication failures). Without it, an attacker can mount unlimited credential stuffing or brute-force attacks against your login, signup, and password-reset routes at no cost. CWE-770 and CWE-307 (improper restriction of excessive authentication attempts) both apply. In serverless environments, an in-memory rate limit resets on every cold start and is effectively no limit at all.

## Severity rationale

Critical because unlimited authentication attempts enable automated credential stuffing and brute-force attacks that compromise user accounts with no server-side barrier.

## Remediation

Add rate limiting in `src/middleware.ts` starting with authentication endpoints. For Next.js on Vercel, use `@upstash/ratelimit` with a Redis-backed sliding window — it works in Edge Middleware and survives cold starts:

```ts
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, '15 m'), // 10 attempts per IP per 15 min
})

const { success } = await ratelimit.limit(ip)
if (!success) return new Response(null, { status: 429 })
```

Apply stricter limits to authentication routes (10/15min), looser limits to general API routes (100/min). Never use an in-memory counter in serverless — it resets on cold start and provides no protection.

## Detection

- **ID:** `rate-limiting`
- **Severity:** `critical`
- **What to look for:** Enumerate all API routes and check for rate limiting on each. Look for: rate limiting middleware (upstash/ratelimit, express-rate-limit, rate-limiter-flexible, slow-down); platform-level rate limiting config (Vercel Edge Middleware with rate limiting, Cloudflare rate limiting rules, API Gateway throttling); manual rate limiting implementation using Redis or a key-value store. Pay particular attention to high-risk endpoints: authentication (login, signup, password reset), payment operations, email-sending endpoints, and any endpoint that is expensive to compute or that exposes sensitive data. Implementation correctness matters: If rate limiting uses a database count query followed by a conditional insert (check-then-act pattern), flag this as a race condition vulnerability — concurrent requests can bypass the limit. Atomic operations are required for correctness: Redis INCR, PostgreSQL advisory locks, database upsert with conflict handling, or a dedicated rate limit library (e.g., @upstash/ratelimit, rate-limiter-flexible). A check-then-act implementation is a FAIL even if the intent is correct.
- **Pass criteria:** Rate limiting is implemented with no more than 100 requests per minute per IP on at least authentication endpoints, expensive operations, and any public-facing API endpoints. The implementation is tied to a persistent store (Redis, Upstash, etc.), not in-memory (which resets on cold start). Limits are reasonable (e.g., not 10,000 req/min per IP).
- **Fail criteria:** No rate limiting of any kind found on any API route. Do not pass when rate limiting exists only in-memory (no persistent store) — this is ineffective in serverless environments. Or authentication endpoints have no rate limiting.
- **Skip (N/A) when:** The project has no API routes accessible without prior authentication AND sits behind an API gateway or proxy that enforces rate limiting. Signal: all routes require auth AND vercel.json or other config shows edge-level rate limiting enforced upstream. (This is rare — default behavior is to fail if no evidence of rate limiting.)
- **Detail on fail:** Example: `No rate limiting on POST /api/auth/login`. Identify which high-risk endpoints lack rate limiting (e.g., "No rate limiting found on POST /api/auth/login, POST /api/auth/register, or POST /api/contact; no rate limit middleware in dependencies"). Max 500 chars.
- **Remediation:** Add rate limiting in `src/middleware.ts` or route handlers to your API immediately, starting with authentication endpoints. For Next.js on Vercel, the easiest approach is Upstash Rate Limit with their `@upstash/ratelimit` package and a Redis database: it works in Edge Middleware and Serverless Functions. Implement a sliding window or fixed window limit (e.g., 10 login attempts per IP per 15 minutes). For self-hosted Express/Fastify, use `express-rate-limit` with a Redis store. Apply rate limiting in middleware rather than per-route to avoid forgetting routes. Log rate limit hits so you can tune the limits.
- **Cross-reference:** For a deeper analysis of authentication security, the SaaS Auth & Sessions Audit covers session management and auth flow security in detail.

## External references

- cwe CWE-770
- cwe CWE-307
- owasp A04
- owasp A07

Taxons: access-control, cost-efficiency

HTML version: https://auditbuffet.com/patterns/ab-002204
