Research / Business logic
Rate limiting is a business-logic control
Rate limiting gets treated as a defense against brute force and little else. In practice it protects workflows, and the workflows it protects are not obvious from a single request.
Rate limiting is usually filed under "stop password guessing," and so it gets applied to the login endpoint and forgotten. But a missing rate limit is a business-logic problem, and the workflows it exposes go well beyond authentication: triggering unlimited emails at a target, enumerating which accounts exist, and turning an invite or notification feature into a way to flood a third party. None of these look dangerous in a single request. They become dangerous at volume, which is exactly what a rate limit governs.
The system assumption
The assumption is that rate limiting is an anti-brute-force control, so its job is to slow down guessing on the login and password-reset forms. That framing is too narrow. Rate limiting is really a control on how often a workflow can be invoked, and many workflows are harmful when invoked too often, not because any single call is a vulnerability, but because the volume is the attack. Viewed one request at a time, an email send is a feature working correctly. Viewed as ten thousand sends aimed at one address, it is abuse the system chose to allow.
Where the assumption breaks
Three patterns recur, none of them about password guessing.
- Email and notification amplification. An endpoint that sends an email (verification, invite, "notify this person") with no per-target limit lets an attacker send many messages to a chosen address using your reputable infrastructure. It is a spam and harassment vector wearing your return address, and it can damage your sending reputation as collateral.
- Enumeration. An endpoint that responds differently for known and unknown accounts, with no rate limit, is a lookup service for "who has an account here." Invite flows, password resets, and sign-up checks are common offenders. Each request is a legitimate feature call; the volume turns it into a directory of your users.
- Workflow denial of service. A feature that acts on a target, an invite that provisions something, a request that consumes a quota, can be driven repeatedly to exhaust a limit or bury a real user in noise. The invite feature becomes a way to deny service to the person being invited.
Reconstructing it
one request (looks fine):
POST /api/invite { email: "target@example.com" } -> 200, email sent
the same request, unlimited, is the attack:
for i in 1..N:
POST /api/invite { email: "target@example.com" } -> 200 x N
N legitimate calls == inbox flood / reputation damage / DoS on the target
Why the obvious defenses didn't solve it
Rate limiting the login only. The most common state we find: the login form is protected, everything else is open. The controls were mapped to the threat "brute force" rather than the property "frequency," so every other frequency-sensitive workflow was left uncovered.
Input validation. Each request is perfectly valid. The email is a real email, the target is a real user, the action is a permitted action. There is nothing malformed to reject; the problem is repetition, which validation does not measure.
CAPTCHA on the wrong forms. A challenge on sign-up does nothing for an authenticated invite endpoint or an internal notification trigger. Anti-automation has to sit on the frequency-sensitive workflow, not only on the pages traditionally associated with bots.
Root cause
The root cause is that rate limiting was scoped to a threat (brute force) instead of a property (how often a workflow may run). Once you see it as a business-logic control, the design question changes from "which forms need anti-brute-force" to "which workflows are harmful at volume, and what is the right limit and scope for each." The answer differs per workflow: some need per-account limits, some per-target, some per-IP, some a combination, and the limit that matters is often per-target rather than per-sender, because the harm accrues to the target.
How to test for this class of failure
- Enumerate every workflow that sends a message, provisions something, consumes a quota, or reveals whether an account exists. For each, ask what happens at a thousand times the normal rate.
- Test limits per relevant dimension, not just per IP. A per-IP limit is trivially bypassed and often misses the real harm; check per-account and per-target as well.
- Probe enumeration directly: compare responses, timing, and side effects for known versus unknown identifiers, and see whether volume is constrained.
- For amplification, measure whether one attacker request produces one outbound effect or many, and whether the target of that effect can be chosen freely.
How to design the control correctly
- Treat frequency as a first-class control. For each sensitive workflow, decide a limit and the dimension it applies to (per account, per target, per IP, or a combination), and enforce it server-side.
- Protect the target, not just the sender. For messaging and invite flows, cap how often a given recipient can be acted on, since that is where the harm lands.
- Make enumeration uninformative. Return uniform responses for known and unknown identifiers, and rate-limit the endpoints that could otherwise be used to build a user directory.
- Fail safe and observably. When a limit is hit, degrade gracefully and log it, so abuse is both blunted and visible rather than silently absorbed.
What we took away from it
Rate limiting is one of the clearest examples of a control that only makes sense when you think in terms of state and workflows rather than individual requests. A scanner firing one request at a time cannot tell you that an endpoint is missing a per-target limit, because one request is the feature behaving correctly. You find these by modeling the workflow and asking what volume does to it. That is the same reason business-logic testing needs a human holding context: the vulnerability is not in any request, it is in the pattern the requests are allowed to form.
References
- OWASP API Security Top 10 (2023): API4 Unrestricted Resource Consumption
- OWASP: Blocking Brute Force Attacks
- CWE-799: Improper Control of Interaction Frequency
- CWE-307: Improper Restriction of Excessive Authentication Attempts
Internal evidence: Kahu Labs Research, anonymized authorized assessments (2023, 2025). Client, target and identifying details are withheld; see our research policy.