# OTP and reset brute force via weak throttling

Short OTP or reset code guarded only by per-IP or non-atomic throttling, guessable concurrently

_Area: Web authentication and account takeover. Seen in 8 disclosed reports; 6 confirmed bounties, median $10,000, range $500-$30,000; latest 2023-07-21. Updated 2026-10-23._

## How it works
A verify or reset step accepts a short secret (4-6 digit OTP, reset code) and relies on a rate limit to make guessing infeasible. The assumption that breaks: that the limit caps total guesses. Two independent failures recur. (1) Key multiplication: the limit is keyed on something the attacker can vary — client IP, or a per-server IP, or an IPv6 address — so each variant gets a fresh budget [E1](https://bugbountylibrary.com/r/blog%3Athezerohack-com-apple-vulnerability-bug-bounty.md)[E2](https://bugbountylibrary.com/r/blog%3Athezerohack-com-hack-any-instagram.md)[E6](https://bugbountylibrary.com/r/blog%3Adhiyaneshgeek-github-io-web-security-2021-10-23-how-i-was-able-to-revoke-your-instagram-2fa.md)[E7](https://bugbountylibrary.com/r/h1%3A1154003.md). (2) Non-atomic counting: the counter is read then written, so concurrent requests all see the pre-increment value and pass [E1](https://bugbountylibrary.com/r/blog%3Athezerohack-com-apple-vulnerability-bug-bounty.md)[E2](https://bugbountylibrary.com/r/blog%3Athezerohack-com-hack-any-instagram.md). Either alone can make the code space reachable within the token's lifetime.

## Where it shows up
- OTP/reset verify endpoints with only per-IP throttling on a short numeric code [E2](https://bugbountylibrary.com/r/blog%3Athezerohack-com-hack-any-instagram.md)[E6](https://bugbountylibrary.com/r/blog%3Adhiyaneshgeek-github-io-web-security-2021-10-23-how-i-was-able-to-revoke-your-instagram-2fa.md)[E8](https://bugbountylibrary.com/r/blog%3Amedium-freecodecamp-org-responsible-disclosure-how-i-could-have-hacked-all-facebook-accounts-f47c0252ae4d.md).
- Limits enforced non-atomically, so parallel requests slip past the stated cap [E1](https://bugbountylibrary.com/r/blog%3Athezerohack-com-apple-vulnerability-bug-bounty.md)[E2](https://bugbountylibrary.com/r/blog%3Athezerohack-com-hack-any-instagram.md).
- A flow protected everywhere except the token-validation step [E3](https://bugbountylibrary.com/r/h1%3A1987062.md)[E4](https://bugbountylibrary.com/r/h1%3A767765.md)[E5](https://bugbountylibrary.com/r/h1%3A703972.md).
- Throttle keyed on client IP where the client controls the IP: IPv6 normalized to /128, so a /64 allocation rotates freely [E7](https://bugbountylibrary.com/r/h1%3A1154003.md).
- A beta/mobile subdomain of the same flow that skips the throttle the production host enforces [E8](https://bugbountylibrary.com/r/blog%3Amedium-freecodecamp-org-responsible-disclosure-how-i-could-have-hacked-all-facebook-accounts-f47c0252ae4d.md).

## How to review
The invariant: total accepted guesses across all IPs and input shapes must stay below the code space within the token lifetime, and the counter must be atomic. Concretely: confirm the counter key includes the account/token ID, not client IP or raw input; per-account keying alone is insufficient, so pair it with a global or per-token cap. Confirm increment-and-check is atomic (single `UPDATE ... RETURNING` or a lock). Test it: fire a parallel burst of guesses and count how many are accepted versus the stated limit. Enumerate every endpoint in the flow and confirm the final validation step is throttled, not just earlier ones [E3](https://bugbountylibrary.com/r/h1%3A1987062.md)[E4](https://bugbountylibrary.com/r/h1%3A767765.md)[E5](https://bugbountylibrary.com/r/h1%3A703972.md). Check how client identity is derived from IP — IPv6 masked to /128 is trivially rotated [E7](https://bugbountylibrary.com/r/h1%3A1154003.md). Check sibling hosts of the same flow [E8](https://bugbountylibrary.com/r/blog%3Amedium-freecodecamp-org-responsible-disclosure-how-i-could-have-hacked-all-facebook-accounts-f47c0252ae4d.md).

## Variants seen
- Race-condition bypass of per-endpoint and per-server limits, concurrent OTP brute force [E1](https://bugbountylibrary.com/r/blog%3Athezerohack-com-apple-vulnerability-bug-bounty.md).
- Per-IP limit on a 6-digit code with a 10-minute expiry [E2](https://bugbountylibrary.com/r/blog%3Athezerohack-com-hack-any-instagram.md).
- Missing throttle on the token-check endpoint only [E3](https://bugbountylibrary.com/r/h1%3A1987062.md).
- No rate limit at all on a 4-char alphanumeric code verify endpoint [E4](https://bugbountylibrary.com/r/h1%3A767765.md).
- Final reset step re-validating the code with no attempt limit [E5](https://bugbountylibrary.com/r/h1%3A703972.md).
- Per-IP OTP limit evaded by rotating source IPs [E6](https://bugbountylibrary.com/r/blog%3Adhiyaneshgeek-github-io-web-security-2021-10-23-how-i-was-able-to-revoke-your-instagram-2fa.md).
- IPv6 /128 normalization lets a subnet rotate past the throttle [E7](https://bugbountylibrary.com/r/h1%3A1154003.md).
- Unthrottled beta/mobile subdomain of a throttled production flow [E8](https://bugbountylibrary.com/r/blog%3Amedium-freecodecamp-org-responsible-disclosure-how-i-could-have-hacked-all-facebook-accounts-f47c0252ae4d.md).

## Why fixes fail
Fixes applied per-method or per-endpoint leave the validation step unthrottled [E3](https://bugbountylibrary.com/r/h1%3A1987062.md)[E4](https://bugbountylibrary.com/r/h1%3A767765.md)[E5](https://bugbountylibrary.com/r/h1%3A703972.md); keying on source IP lets the client pick its own key [E6](https://bugbountylibrary.com/r/blog%3Adhiyaneshgeek-github-io-web-security-2021-10-23-how-i-was-able-to-revoke-your-instagram-2fa.md)[E7](https://bugbountylibrary.com/r/h1%3A1154003.md); applying the throttle to production but not sibling hosts reopens the channel [E8](https://bugbountylibrary.com/r/blog%3Amedium-freecodecamp-org-responsible-disclosure-how-i-could-have-hacked-all-facebook-accounts-f47c0252ae4d.md).

## Impact and severity
Full account takeover of any user, including high-value accounts [E1](https://bugbountylibrary.com/r/blog%3Athezerohack-com-apple-vulnerability-bug-bounty.md)[E2](https://bugbountylibrary.com/r/blog%3Athezerohack-com-hack-any-instagram.md)[E8](https://bugbountylibrary.com/r/blog%3Amedium-freecodecamp-org-responsible-disclosure-how-i-could-have-hacked-all-facebook-accounts-f47c0252ae4d.md). Severity is high; worse with short codes, long or absent expiry windows, and many usable egress IPs.

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Athezerohack-com-apple-vulnerability-bug-bounty.md
- E2: https://bugbountylibrary.com/r/blog%3Athezerohack-com-hack-any-instagram.md
- E3: https://bugbountylibrary.com/r/h1%3A1987062.md
- E4: https://bugbountylibrary.com/r/h1%3A767765.md
- E5: https://bugbountylibrary.com/r/h1%3A703972.md
- E6: https://bugbountylibrary.com/r/blog%3Adhiyaneshgeek-github-io-web-security-2021-10-23-how-i-was-able-to-revoke-your-instagram-2fa.md
- E7: https://bugbountylibrary.com/r/h1%3A1154003.md
- E8: https://bugbountylibrary.com/r/blog%3Amedium-freecodecamp-org-responsible-disclosure-how-i-could-have-hacked-all-facebook-accounts-f47c0252ae4d.md
