Skip to content
nviaOTP

Threat Modeling OTP Flows · Chapter 5 of 6

SMS pumping / toll fraud as an OTP-flow threat

An attacker who never wants your accounts can still bill you. Model the send endpoint as an asset and gate it accordingly.

6 min read

Every attack so far targeted an account. SMS pumping targets your budget. The attacker submits large numbers of OTP requests to phone numbers they have arranged to profit from — typically premium-rate or high-cost ranges where a share of the termination fee flows back to them through a complicit party somewhere in the chain. No one ever types a code. The login never completes. Your only evidence is the bill and a curious spike in verification requests that never verify.

This chapter treats pumping strictly as a threat to the OTP flow you own: the send endpoint and the logic in front of it. How messages are routed and priced after they leave your system belongs to a different discipline and is deliberately out of scope here.

Why OTP flows are the target

OTP send endpoints have three properties attackers love. They are reachable without authentication, because the user is not signed in yet. They trigger a paid action on every call. And they accept a destination chosen by the caller. Combine those and you have a public API that spends your money at an address the attacker picks. Signup forms, password resets, “send me a link to the app” buttons and phone verification for checkout all share the pattern.

The pumping loop. The fictional range shown is reserved for drama and documentation; real attacks use whatever ranges pay best that week.

Attacker view

My business model

  • Your form needs no account, so I need no credentials.
  • I pick the destination numbers.
  • Your bot checks are weaker on the signup page than on login.
  • You will notice at month-end, not in real time.

Defender view

Gates in front of the send

  • Conversion rate monitoring per country prefix, in near real time.
  • Allow-list of countries you actually serve; deny the rest by default.
  • Proof of work or a challenge before the first send from a new client.
  • Per-prefix and global spend caps that fail closed.

The one metric that matters

Legitimate OTP traffic has a high verification rate: most people who request a code type it. Pumped traffic has a verification rate near zero, because no human is waiting. Tracking verify rate per destination prefix per hour is therefore the most reliable detector you can build, and it is cheap. When a prefix that normally converts at eighty percent drops to five percent while volume climbs, you are being pumped. The figures here are an illustrative example; derive your own baselines from a few weeks of history.

-- verify rate by prefix over the last hour (illustrative schema)
select left(destination, 6) as prefix,
       count(*)                                 as sent,
       count(*) filter (where verified_at is not null) as verified,
       round(100.0 * count(*) filter (where verified_at is not null) / count(*), 1) as verify_pct
from otp_sends
where created_at > now() - interval '1 hour'
group by 1
having count(*) > 20
order by verify_pct asc;
Sort ascending: the prefixes at the top with high volume and low conversion are your incident.

Controls in layers

The first layer is scope. If Pinecrest serves patients in two countries, its send endpoint should refuse every other country code unless an operator explicitly enables it. This single control eliminates most pumping exposure for regional services. The second layer is friction for new clients: a lightweight challenge or proof-of-work before the first send from a device or IP the system has not seen, which raises the attacker’s cost per message without bothering returning users.

The third layer is rate limiting keyed carefully, which series 4 covers in depth: per destination number, per prefix, per client and globally. The fourth is a circuit breaker. When the verify rate for a prefix falls below a threshold with meaningful volume, stop sending to that prefix automatically and page someone. A breaker that fails closed costs some legitimate sends during an incident; one that fails open costs your budget.

  • Country allow-list at the send endpoint, deny by default.
  • Challenge before first send from an unseen client.
  • Per-number, per-prefix, per-client and global limits.
  • Automatic prefix breaker on verify-rate collapse, with paging.
  • Daily spend cap with an alert at fifty percent.

An illustrative example of what happens without these: on the night of 2026-10-10, Pinecrest’s signup form received 41,000 OTP requests in three hours to sequential numbers in four country codes it had never served. Verify rate across those prefixes was 0.02 percent. At an assumed blended cost of a few cents per message, the night would have cost more than a month of normal traffic. The prefix breaker, added the week before, tripped after eleven minutes and capped the damage at under four percent of that figure.

Recording it in the model

Pumping is a financial threat, so the severity rubric should weigh cost. For a service with an unrestricted, unauthenticated send endpoint, the inherent rating is high or critical depending on budget. With an allow-list and a breaker, residual risk is usually low. With only rate limits, it stays medium, because distributed attackers can stay under per-client limits while still generating large aggregate volume.

ThreatInherentMitigationResidual
Pumping via unauthenticated signupCriticalCountry allow-list + prefix breaker + spend capLow
Pumping via password resetHighSend only to already-verified numbersLow
Distributed low-rate pumpingMediumGlobal limits + verify-rate monitoringMedium

Watch for the shape of the destinations too. Pumping runs often target sequential or near-sequential numbers within a small block, because the attacker controls a contiguous range. A simple check that counts distinct numbers sharing a long prefix within an hour catches many runs before the verify-rate signal is statistically clear. Combine it with the breaker rather than replacing it.

Finally, involve finance. Pumping incidents surface first on invoices, so the people who read those invoices should know what the pattern looks like and whom to call. A daily spend report by country, shared with both engineering and finance, is a cheap control that has caught real incidents faster than any dashboard nobody was watching.

Rehearse it like any incident: a quarterly game day that replays synthetic pumping traffic against staging proves the breaker trips, the page arrives and the on-call engineer knows how to reopen a prefix safely.

0/3 correct · 0 answered

  1. 1. What is the most reliable real-time pumping signal?

  2. 2. Which single control removes most pumping exposure for a regional service?

  3. 3. Why should the prefix breaker fail closed?

Discussion

Comments are public and shared with every reader. No account needed — just a display name. Comments reported by three readers are hidden automatically.

15 more characters needed

Loading comments…