Two endpoints, two different attacks
OTP brute-force protection is one half of a two-front problem: an OTP flow has two endpoints an attacker can target, and they need different defenses. The *send* endpoint is attacked by SMS pumping: bots trigger paid messages to inflate traffic. The *verify* endpoint is attacked by brute force: an attacker who has a target's phone but not the code (or is guessing blind) submits attempt after attempt until they hit the right six digits. Teams often defend the send side and forget the verify side, which is a serious gap: a 6-digit code is only a million possibilities, and a million guesses is nothing to an automated script. Without limits, brute force against verify is not hard: it's arithmetic.
The defenses are simple and cheap, but they have to be deliberate. Here's the math that shows why, and the caps that close it.
The math that makes limits mandatory
A 6-digit numeric code has 1,000,000 possible values. That sounds like a lot until you consider an attacker making automated guesses against an unprotected verify endpoint.
| Defense | Guesses an attacker gets | Chance of success |
|---|---|---|
| No limit | Unlimited | 100% eventually — trivially broken |
| Cap at 5 attempts per code | 5 | 5 in 1,000,000 (0.0005%) |
| Cap + invalidate code after limit | 5, then the code is dead | 0.0005%, no second window |
| Longer code (8 digits) + cap | 5 of 100,000,000 | Negligible |
Five attempts against a million-value space is a 1-in-200,000 shot per code — and if you *invalidate the code* after the fifth wrong try, the attacker can't just request the space over. Caps plus invalidation is the core of the defense; the OTP best-practices defaults bake both in. This approach aligns with NIST SP 800-63B guidelines on verifier impersonation resistance and rate limiting (NIST SP 800-63B).
The layered verify-side defense
- Cap attempts per code, then invalidateFive wrong attempts and the code is dead — the user must request a fresh one. This is the single most important control; it turns an unlimited search into a 5-in-a-million shot.
- Rate-limit verify requests per identityBeyond per-code caps, limit verify attempts per account/session/IP over time — the token-bucket approach applied to the verify endpoint, so an attacker can't cycle through many codes rapidly.
- Enforce short code expiryA 5-minute TTL shrinks the window an attacker has to guess before the code dies naturally — a second dimension of the same limit.
- Detect and lock on abuse patternsRepeated cap-hits on one account signal an attack; add friction (CAPTCHA, temporary lockout, alert) rather than silently letting it continue. Log it for your security monitoring.
Combine them and brute force becomes infeasible: 5 attempts per code, code invalidated after, short expiry, and per-identity rate limits on top. Brute-force defense is one part of the broader SMS 2FA picture, and it sits alongside the send-side and identity defenses mapped in the SMS security guide.
Defending both endpoints together
Because the send and verify endpoints face different attacks, a complete OTP defense needs both sets of controls. Send-side: per-number and per-IP send caps plus number validation against pumping. Verify-side: per-code attempt caps with invalidation plus per-identity rate limits against brute force.
SMSRoute is a no-KYC SMS API with crypto billing (BTC, ETH, USDT, XMR, LTC, and SOL), and it delivers the codes. The verify logic (where brute-force defense lives) runs in your backend, which is exactly where it belongs. You own the attempt caps, the invalidation, the rate limits, and the abuse detection. Build both endpoints' defenses, and your OTP flow is secure on the two fronts attackers actually probe. SMSRoute's published route pages list delivery from $0.004/message (premium direct-carrier corridors up to $0.035) with sub-100ms median submission and ~98.6% delivered success (smsroute.cc route pages, 2026).
Related reading
FAQ
How do I protect an OTP endpoint from brute force?
Is a 6-digit OTP secure enough?
What's the difference between OTP brute force and SMS pumping?
Should I invalidate an OTP code after failed attempts?
Send your first SMS in 5 minutes
No KYC. Pay with BTC, ETH, USDT, XMR, LTC, and SOL. Live routes to 149 countries.
Get an API key →