medium Web Vulnerabilities

Missing Rate Limiting (Brute-Force)

Login and form endpoints accept unlimited attempts, letting attackers brute-force passwords at full speed.

Severity
medium
Time to Fix
2-4 hours
Difficulty
medium
OWASP
A07:2021 — Identification and Authentication Failures

What is Missing Rate Limiting (Brute-Force)?

When a login form, password-reset endpoint, or API route accepts unlimited requests, attackers can test passwords (or stolen credential pairs) as fast as the server and network allow. The dominant attack is credential stuffing: bots replay username/password pairs from unrelated breaches against your login, because passwords are reused. Without throttling there is nothing that slows them down — a single machine can test hundreds of thousands of combinations per day against one form. Rate limiting (progressive delays, request quotas per IP and per account, lockouts, and CAPTCHA escalation) turns that firehose into a trickle and makes attacks uneconomical.

Why It Matters to Your Business

Missing rate limiting converts password reuse into account takeover at industrial scale. Beyond account breaches, unthrottled endpoints are abused for resource exhaustion (cheap DoS), SMS/email bombing of reset endpoints (costing you per message and harassing your users), and scraping. It is an OWASP Top 10 category (A07) finding that appears in every security review, and fixing it is a few lines of middleware.

How to Fix It

Laravel (throttle middleware — per-IP by default):
  Route::post('/login', [AuthController::class, 'login'])
       ->middleware('throttle:5,1');   // 5 attempts per minute per IP

  // For login specifically, rate-limit per ACCOUNT too (defends distributed attacks):
  RateLimiter::for('login', function (Request $r) {
      return Limit::perMinute(5)->by($r->input('email').'|'.$r->ip());
  });

Nginx (generic request quota):
  limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
  location = /login { limit_req zone=login burst=3 nodelay; }

Express: express-rate-limit. Django: django-ratelimit or DRF throttle classes.

Escalate in layers: throttle -> CAPTCHA after N failures -> temporary lockout -> alert. Add MFA and the stolen-password problem largely disappears regardless of attempt speed.

Frequently Asked Questions

How many login attempts should I allow?

A practical baseline: 5 attempts per minute per IP, plus a per-account counter (e.g. 10 failures triggers a 15-minute cooldown or CAPTCHA). Humans rarely trip this; bots constantly do. Always pair per-IP and per-account limits — either alone is bypassable.

Is a CAPTCHA enough instead of rate limiting?

No — modern CAPTCHA solvers are cheap and automated. Use CAPTCHA as an escalation layer after throttling triggers, not as the primary control. Throttling cannot be solved; it can only be distributed.

Does Cloudflare already rate-limit my site?

Partially — Cloudflare's free WAF and bot tools blunt large floods, but per-account logic and application-aware limits still belong in your app. Distributed, low-and-slow attacks walk right through generic network-level rules.

Technical Classification

OWASP CategoryA07:2021 — Identification and Authentication Failures
CWE IDCWE-307: Improper Limitation of the Number of Login Attempts
Detected Byrate_limit scanner(s)
Severity Levelmedium

How 2MNY Security Can Help

Check if your website has this vulnerability

Our rate_limit scanner checks for this issue automatically.

Scan My Website Free

Related Vulnerabilities