Improper Restriction of Authentication Attempts
Summary
This is the missing-rate-limit class: a login, registration, password-reset, or OTP-verification endpoint accepts an unlimited number of attempts from the same client with no throttling, lockout, or CAPTCHA challenge kicking in. On its own it enables credential-stuffing and password-spraying against the login form; combined with a weak or predictable OTP/reset-token (commonly 4-6 digits) it becomes fully exploitable account takeover, since a short numeric space can be exhausted in seconds without rate limiting. Unlike most native-code or logic-flaw categories, this one is directly and repeatably testable from outside: send a burst of requests and observe whether the server ever pushes back.
Top Affected Components / Targets
/loginand other primary-credential endpoints/register(used for account-enumeration and mass-signup abuse, not just login)/forgot-passwordand/reset-password(short numeric/alphanumeric reset codes are the highest-impact variant)- OTP/2FA verification endpoints (6-digit codes are a 1,000,000-value space - trivially exhaustible without throttling)
- Any endpoint gating an account-linked action behind a PIN or short shared secret
Common Attack Vectors
- Fire N consecutive login attempts with a fixed username and varying passwords, checking whether request N+1 still returns the same response shape/timing as request 1
- Same burst against
/forgot-passwordor an OTP-verification endpoint, where a fixed-length numeric code makes brute force tractable within a lockout-free window - Distribute the burst across rotating
X-Forwarded-Forvalues to check whether rate limiting is keyed on a spoofable header instead of the actual connection - Check whether a lockout, once triggered, is scoped per-account (safe) or per-source-IP only (bypassable by any attacker with several IPs)
Common Payloads
- A fixed burst count (commonly 10-20) of otherwise-identical POST requests to the target endpoint, sent back-to-back with no artificial delay
- Sequential OTP guesses (000000-999999) at whatever rate the endpoint allows
Detection Strategy
Fire a burst of requests at authentication-sensitive endpoints (/login, /register, /forgot-password) with deliberately incorrect credentials and inspect whether every request in the burst succeeds identically - same status code, same response shape, no CAPTCHA challenge, no 429/lockout response appearing anywhere in the sequence. Absence of throttling across the full burst is a deterministic, low-false-positive signal: a correctly configured endpoint will show some behavioral change (429, CAPTCHA, delay, temporary lockout) well before the burst completes. This check deliberately stays below the volume that would constitute an actual credential-stuffing attack against the real target - it proves the absence of a control, not a successful compromise.
Tip: Testing tools that run these checks in parallel across every discovered endpoint can cut the time required substantially compared to fully manual testing, as long as they confirm findings with more than one signal to keep the false-positive rate down.
False-Positive Notes
- Some applications rate-limit after a threshold higher than a short test burst (e.g. allow 50 attempts before triggering a lockout) - a burst of 10-20 requests all succeeding is still meaningful signal (a real attacker can run far more than 20 attempts), but treat this as the deterministic floor rather than proof no limiting exists at any volume.
- WAF-level rate limiting (Cloudflare, AWS WAF) sitting in front of the app can mask an application-level gap or produce a false negative if the burst is small enough to stay under the WAF's own threshold - this is a known blind spot, not a false positive, and is why the finding is scored as a real gap rather than dismissed.
How to Test
Manual Testing Methodology
Here is a systematic approach to identifying Improper Restriction of Authentication Attempts vulnerabilities in a target application.
Before testing, map all input vectors that could be affected. Identify parameters, headers, cookies, and request bodies that interact with the vulnerable component. A proxy such as Burp Suite or OWASP ZAP, paired with normal browsing of the target, is usually enough to build this list.
Send a legitimate request and record the normal response: status code, content length, response time, and any identifying tokens. This baseline matters because it's what you'll compare later responses against once payloads are involved.
Inject test payloads into each identified input vector one at a time. Start with benign detection payloads before escalating to anything that could actually trigger the vulnerability. For Improper Restriction of Authentication Attempts specifically, send a burst of requests against the target endpoint (login, password reset, MFA code, or a pagination/size-controlled parameter) well beyond what a legitimate user would generate in the same window, from both a single IP and, where feasible, multiple sources.
Compare the response against your baseline, looking specifically for whether the request volume is accepted without throttling, delay, or lockout — and separately, whether resource-controlling parameters (page size, requested item count) can be set high enough to measurably degrade response time or server load.
Once a potential vulnerability is detected, confirm it with at least a few independent test cases to rule out coincidence. Document the exact request and response as proof. For Improper Restriction of Authentication Attempts, a confirmed finding typically means showing that attacker-controlled input changes the application's behavior in a way that matters for security, not just that a payload was reflected somewhere harmless.
Real-World Impact
Real-World Impact
Missing rate limiting on authentication and other sensitive endpoints turns what should be a slow, detectable attack into a fast, automatable one. Without a cap on attempts, credential stuffing and password-spraying campaigns can run at whatever speed the attacker's infrastructure allows, and password-reset or MFA-code endpoints without a limit become brute-forceable in a realistic timeframe.
The same underlying gap — no bound on how much of a resource a single request or account can consume — also enables denial-of-service through resource exhaustion: unbounded pagination, unbounded file-processing size, or unbounded concurrent request creation can degrade or take down a service without needing a "real" logic vulnerability at all.
This class of finding is frequently underrated relative to its actual risk, since a single unrated request looks harmless — the impact only becomes obvious once it's run at scale, which is exactly what an attacker will do.
Prevention & Remediation
Prevention and Secure Coding
Preventing Improper Restriction of Authentication Attempts takes a defense-in-depth approach — no single control below is sufficient alone, but together they close off both the primary path and the most common bypasses.
Rate-limit per account and per IP. Apply limits on both axes for authentication, password-reset, and MFA-code endpoints — per-IP alone is defeated by distributed sources, and per-account alone is defeated by targeting many accounts slowly.
Progressive lockout, not a hard ceiling alone. Increasing delays or temporary lockouts after repeated failures slow an attacker meaningfully without permanently locking out a legitimate user who mistyped a password a few times.
CAPTCHA or proof-of-work after a threshold. Add friction after a small number of failures rather than either allowing unlimited attempts or blocking outright, which balances usability against abuse.
Explicit resource limits everywhere, not just login. Cap pagination size, upload size, and any operation whose cost scales with a client-supplied number, so a single request can't consume disproportionate server resources.