Protect your Twilio Account Against Phone Number Fraud

January 12, 2023
Written by
Reviewed by

Protect your Twilio Account Against Phone Number Fraud

In this article I want to raise awareness of a class of fraudulent schemes such as toll fraud and SMS traffic pumping that are unfortunately on the rise. The interesting fact about them is that you become a victim simply by placing calls or sending SMS to certain phone numbers that are owned by the scammer. I’m also going to share a few techniques that you can use to avoid falling victim to these scams, and more importantly, prevent unexpected charges in your Twilio bill.

How do fraudsters use phone numbers to make money?

There are two main attack vectors based on fraudulent phone numbers, both designed to generate additional usage charges in your Twilio account.

In the scheme known as toll fraud the scammer generates spurious calls to premium numbers, which phone companies in many countries offer for sale. These are numbers that charge the caller a high rate per minute, with the generated revenue shared between the phone company and the owner of the line. The intended use cases for these numbers are tech support, psychic or adult chat hotlines and other similar businesses where callers pay for a service by the minute through their phone bill.

Premium numbers are often exploited by scammers, who legally obtain these numbers and then find ways to generate calls to them, usually by taking advantage of the user verification features of many unsuspecting websites or apps which immediately place a call to a given number. With a high enough volume, this can be very lucrative for the scammer, while the Twilio account used by the victim to make the calls is billed at premium number rates.

The SMS traffic pumping scam, also known as artificially inflated SMS traffic fraud, has the end goal of sending a large number of SMS to designated mobile numbers, also by exploiting account verification, password reset requests and similar flows in victim websites or apps. The scammer obtains the numbers from smaller mobile operators with which they have a revenue sharing agreement.

How to prevent phone number fraud?

The main tool you have as a Twilio developer to avoid falling victim to these scams is to validate phone numbers provided by users before making calls or sending SMS to them in your application.

There are several validation strategies that you can use depending on your needs. The approaches described in the following sections should keep your risk low.

Restrict your geographic permissions

Many bad actors are able to obtain numbers intended for fraud in third-world countries with lax regulations. If your business operates in a specific list of countries, then a simple and effective option that you have to limit your exposure to phone number fraud is to restrict your account to only be able to call and send SMS to a short list of allowed countries.

This is easily configured in the Twilio Console, but be aware that allowed countries for different products are configured separately. Use the following links to access the configuration pages for geographic permissions:

Twilio recommends only enabling the countries in which you plan on doing business. In the case of voice calling, it is best to only enable “low risk” area codes in these countries unless you have a good reason to work with area codes that Twilio deems as high risk for fraud.

Validate phone numbers with the free Twilio Lookup service

The Twilio Lookup API can validate a phone number and provide information about it such as its country of origin or its canonical representation in E.164 format. This can help you discard invalid numbers right when the user provides them, and before you use them and are charged for connecting to them. The country information provided by this service can be a good alternative to filter numbers by location when the geographic permissions mentioned above are not used.

Here is an example that validates a phone number in a curl request issued from the terminal:

curl -X GET "https://lookups.twilio.com/v2/PhoneNumbers/4159929960?CountryCode=US" -u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN

The phone number can be given in E.164 or national formats. If given in national format as shown in the example above, the CountryCode argument in the query string specifies the country’s two letter code, with a default of US when not given. If the phone number is given in E.164 format, then the country is determined from the number itself.

The TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN environment variables are used to authenticate to Twilio with your account. These are assumed to have been set to the account’s Twilio credentials, which can be found in the Console.

The response to this request is a JSON blob with information about the phone number:

{
    "valid": true,
    "phone_number": "+14159929960",
    "national_format": "(415) 992-9960",
    "country_code": "US",
    "calling_country_code": "1",
    "validation_errors": [],
    "url": "https://lookups.twilio.com/v2/PhoneNumbers/+14159929960",
    "line_type_intelligence": null,
    "call_forwarding": null,
    "identity_match": null,
    "live_activity": null,
    "sim_swap": null,
    "caller_name": null
}

Using this API, any phone numbers that come back with the valid attribute set to false should be rejected, and the user should be asked to re-enter the number. For valid numbers, the phone_number field contains the canonical E.164 format for the number, which is probably the representation that you’d want to store in your user database. The national_format can, in some instances, be used to present the number to the user in a more familiar format, possibly showing the country name, since this format does not include it.

The above example with curl should be easy to translate into the programming language you use, but if you prefer to work with a high-level library, Twilio provides free and open source helper libraries for many languages. The Lookup documentation includes an example similar to the above for all available programming languages.

Formatting and validation requests to the Twilio Lookup service are provided to Twilio users at no cost, so there is really no reason not to take advantage of these features!

Use the Line Type Intelligence package for Twilio Lookup

The Twilio Lookup service can provide additional information beyond the basic validation and formatting shown in the previous section. The “Line Type Intelligence” package is an interesting option that can provide more information to help you decide whether you want to accept a phone number or not.

To enable line intelligence information, the Lookup request must include a Fields argument set to line_type_intelligence in the query string, as shown in the next example:

 curl -X GET "https://lookups.twilio.com/v2/PhoneNumbers/4159929960?CountryCode=US&Fields=line_type_intelligence" -u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN

The response includes all the same fields as before, but the line_type_intelligence section is now returned with additional details.

{
    "valid": true,
    "phone_number": "+14159929960",
    "national_format": "(415) 992-9960",
    "country_code": "US",
    "calling_country_code": "1",
    "validation_errors": [],
    "url": "https://lookups.twilio.com/v2/PhoneNumbers/+14159929960",
    "line_type_intelligence": {
        "type": "nonFixedVoip",
        "carrier_name": "Twilio - SMS/MMS-SVR",
        "mobile_country_code": "311",
        "mobile_network_code": "950",
        "error_code": null
    },
    "call_forwarding": null,
    "identity_match": null,
    "live_activity": null,
    "sim_swap": null,
    "caller_name": null
}

The most important of the line intelligence attributes is type, which tells you the kind of phone line this is. The complete list of values is included in the documentation, but the four that often represent real phone lines owned by users are:

  • landline
  • mobile
  • fixedVoip (Internet phone lines that include a physical device, e.g. Vonage)
  • nonFixedVoip (Internet phone lines obtained online, e.g. Twilio and Google Voice)

Other line types that are usually not a good idea to accept in applications include:

  • premium
  • sharedCost
  • voicemail
  • pager

The most secure approach is to create a list of line types that you are willing to accept, and then any phone numbers that have a line type that is not in this list are rejected. A sensible approach is to accept mobile for SMS, and landline and mobile for voice calls. Depending on the use case, the VoIP types may be added as well.

A pair of interesting line intelligence fields are mobile_country_code and mobile_network_code, which together can be used to do more advanced filtering based on carriers.

If you prefer to use one of the Twilio Helper Libraries to obtain this information, see the documentation, which includes examples for all available programming languages.

The line type intelligence is unfortunately not included in the free tier of the Twilio Lookup service. See current pricing information for this service.

Given that this level of service is not free, you should try to reduce your Lookup calls as much as possible. When you issue a line intelligence query for a number, you may consider caching the results (or at least a valid/not valid boolean) in a database such as Redis for a period of, for example, 24 hours. Targeted attacks often happen over a short period of time, with the victim’s website being flooded with new account requests, all providing the same short list of fraudulent phone numbers for account verification. A 24 hour phone number cache would allow you to protect your Twilio account in two ways:

  1. For a phone number that was rejected as invalid the first time it was seen, the cache will allow your application to “remember” that this phone number should not be accepted without having to make any additional API calls to Twilio.
  2. For a phone number that was validated and accepted, the cache will let your application notice if someone attempts to use the number again for another account, which could also be an indication that fraud is at play. Depending on the needs of your application you may reclassify the number as invalid in your cache when this happens.

An important clarification that needs to be made is that the Lookup service should be used at the time the user signs up for a new account and provides a phone number for the first time. Once a number is validated and stored in your user database, it isn’t necessary to re-verify it every time the application needs to place a call or send an SMS.

To prevent abuse in existing accounts with numbers that have already been validated, a good practice is to implement reasonable limits on the number of calls or SMS made to a phone number over a period of time. This can also be implemented using a cache or database, without the need to use any Twilio services.

Use Twilio Verify’s Fraud Guard

The last suggestion is for those who use Twilio Verify. This service offers Fraud Guard, a free option that monitors SMS sending patterns to detect and block suspected fraudulent numbers. If you are using Twilio Verify to send out verification text messages it is highly recommended that you enable Fraud Guard as an additional layer of protection.

Conclusion

In this article you have learned how fraudsters make money when you place calls or send SMS to their phone numbers. You have also learned four ways to help secure your Twilio account against the growing number of voice and SMS related scams. Implementing as many of these as possible will go a long way to limit your exposure to these attacks.

I can’t wait to see what you build securely with Twilio!

Miguel Grinberg is a Principal Software Engineer for Technical Content at Twilio. Reach out to him at mgrinberg [at] twilio [dot] com if you have a cool project you’d like to share on this blog!