Stop 12 of 42 · The ID Desk · Missing rate limits

Unlimited PIN guesses

Alice’s account is protected by a four-digit PIN. There are only 10,000 possibilities, and the clerk never counts mistakes. Mallory sits at the desk and just keeps trying, one code after another, until the right one comes up.

Severity Info to HighCategory Auth WeaknessThe ID DeskSources checked 25 Oct 2026

Watch it happen

Play it as

Mallory tries PIN after PIN. Nobody counts her wrong attempts, so she eventually finds the right code.

Arrival

Alice’s account is protected by a four-digit PIN: 10,000 possible codes. Alice and Mallory both walk up to the bank.

1 / 5

In bank terms and app terms

In the bankIn your app
PIN guesses at the ID deskRequests to /login, /reset, /otp or /api/token
Clerk counting mistakesA rate limiter counting requests per IP and per account
Guard blocking a seat429 Too Many Requests, or a temporary lockout
10,000 possible PINsShort passwords, 4–6 digit codes and OTPs

Are you exposed?

You might be exposed if…
  • You can send 100 wrong logins in a row to your own app and none are blocked.
  • Login, signup, reset and code-check routes are plain API routes with no limiter in front.
  • You use short numeric codes (OTP, PIN, invite codes) without a lockout or expiry.
What to do about it
  1. Add a rate limiter (for example Upstash Ratelimit, express-rate-limit, or your provider’s built-in limits) to every auth route.
  2. Limit by account as well as by IP, since robbers rotate IP addresses.
  3. Add increasing delays or short temporary lockouts after repeated failures (permanent lockouts let robbers lock real customers out), plus alerts for spikes. Against credential stuffing, MFA and breached-password checks help most.

Track these in your to-do list →

It has happened to real companies

Real-world breaches

iCloud (2014) — The authors of a tool called iBrute claimed it used Apple's Find My iPhone API to guess passwords because the API lacked brute-force countermeasures. After the celebrity photo leaks, Apple said the accounts were compromised by a very targeted attack on user names, passwords and security questions, and not by a breach of its systems, including iCloud or Find My iPhone. It was never confirmed that iBrute was used in those leaks, but unlimited password guessing is exactly what rate limits are meant to stop.

Dunkin' Donuts (2015) — Starting in early 2015, attackers ran credential stuffing attacks (automated logins using usernames and passwords stolen from other sites) against Dunkin' customer accounts, and tens of thousands of dollars were stolen from stored-value DD cards. In 2020 Dunkin' agreed to pay New York State $650,000 in penalties and costs and to put safeguards in place against future attacks.

What it looks like in code

// GOOD: Use a rate limiting library
import { Ratelimit } from "@upstash/ratelimit"
import { Redis } from "@upstash/redis"

const limiter = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(5, "1m"),  // 5 attempts per minute
})

export async function POST(request: Request) {
  // Behind a trusted proxy (e.g. Vercel) the first hop is the client. Also consider limiting per account.
  const ip = request.headers.get("x-forwarded-for")?.split(",")[0].trim() ?? "anonymous"
  const { success } = await limiter.limit(ip)

  if (!success) {
    return NextResponse.json({ error: "Too many attempts" }, { status: 429 })
  }
  // ... login logic
}

Ask your AI tool to fix it

Paste this into Cursor, Claude, Lovable, Bolt or whatever you build with.

Prompt
Add rate limiting to every authentication-related route in my app: login, signup, password reset, OTP/verify and token endpoints. Limit to about 5 attempts per minute per IP and per account identifier, return 429 with a Retry-After header, and use a shared store such as Redis/Upstash so limits work across serverless instances. Prefer short temporary blocks over permanent lockouts. Show me which routes you changed.

Where this comes from

The facts, figures and fixes on this page were checked against these sources on 25 Oct 2026. They are linked so you can check for yourself.

Spot a mistake or something out of date? Report a correction · How these guides are made and checked

Go deeper in isitsecure

The free, open-source scanner checks for most of the problems in these guides.