With Twitter disabling text message two-factor authentication, I thought it’d be fun to do a deep-dive into how SMS fraud works and how app developers can guard against it.

It’s a fascinating story of perverse incentives, short-sighted regulation, and technical ingenuity.

Let’s dig in! 👇

Premium numbers

To start, let’s recap Twitter’s recent announcement:

https://twitter.com/TwitterSupport/status/1626757587524890624?embedable=true

In plain English, this simply means that only users of the paid version of Twitter will get a code sent to their phone during login.

The key to understanding SMS fraud is understanding that some numbers are premium. If you want to call or send an SMS to this number, it’ll cost you some money — typically tens of cents — and the owner of the number gets a portion of those tens of cents for themselves.

Owners of these phone numbers typically offer legitimate services that cost money to supply and offer value to their users, such as tele-voting, dating, and tech support.

However, these numbers can be gamed for easy profit 🤑

SMS fraud

A bad actor, let’s call him Bob, gets hold of several premium phone numbers[1]. Bob could be a hacker, or could be a mobile phone network operator gone bad.

Bob finds a web service that will send text messages to his premium phone numbers. These messages could be two-factor authentication codes, one time passwords, or any other text message sent to the user as part of the service (eg partiful.com sends event reminders via SMS).

Bob finds a way to make the service send thousands of SMSs to his premium phone numbers. This might be very easy. The front end service might be easy to manipulate, and the backend endpoints might be unprotected and easy to reverse-engineer.

Even worse, many services use a standardised endpoint for sending SMSs. This makes it vastly easier to for Bob to find sites to attack. For example, if the service uses a third party for authenticating users and sending out 2FA or OTP codes, such as Auth0, then the endpoint for sending SMSs is mostly known: all Bob needs to do is to figure out a way to discover the Auth0’s ID for a web service (fairly easy, since the web service’s front-end makes a request containing this ID), and then they can attack all sites that use that third party service.

Finally, Bob makes the service send thousands of SMSs to his premium phone numbers. The web service loses 💵💵💵, and Bob profits.

Guarding against SMS fraud

There’s no one silver bullet to prevent SMS fraud. But here are a few ideas that could work:

A good solution would make use of enough of the approaches above, prioritising by time investment and effectiveness, until the attackers move onto easier targets.

I’ve got some personal experience implementing the above measures, and have a story or two to share about how my team handled the fallout. But that’s a story for another time… 👨‍💻

Blocking SMS fraud at the source

This brings me to my final point:

IMO, Twilio — a dominant SMS API — has a huge opportunity to offer SMS fraud protection as a (free? 🙏) add-on to their standard APIs.

Since Twilio has data on fraudulent phone numbers and carriers across all their accounts, Twilio are in the unique position to block bad numbers and carriers fast — before they becomes a big issue for multiple web services.

Twilio can even detect invalid phone numbers outright using Silent Network Auth — a next-generation authentication mechanism — and it feels like this utility ought to be shared between their users.

I’d love to hear any other thoughts, ideas and approaches folks have used — please share by writing a comment below, and we can all learn.

That’s it for now — protect those endpoints, and have a great week!

There’s an excellent discussion on HackerNews.

[1] Note that these premium phone numbers don’t even need to work: they don’t need to be connected to a SIM card that is working and registered to a phone. As long as they can be routed to, they can be used in this attack.

[2] I’m curious if there’s a good data structure and algorithm to make this efficient and work at scale. Please share if you know of one!

[3] Credit to @csharpminor on HN for their suggestion.

I'm Apu, CTO of koodos, and an engineer.

This post originally appeared on my personal blog - subscribe for more like it!