Build a carrier block list with Twilio Lookup

September 01, 2021
Written by
Reviewed by
Mia Adjei
Twilion

Build a carrier block list with Twilio Lookup

Bad actors can target phone verification or two-factor authentication flows to artificially inflate SMS traffic. Certain carriers, knowingly or not, allow this to happen and the fraudsters make money off of this inflated traffic. This could lead to higher than expected Twilio traffic for you.

Our Verify API for sending one-time passcodes includes comprehensive fraud mitigation mechanisms. However, no provider-side solution can guarantee 100% effectiveness against sophisticated attackers, which is why we encourage customer participation in preventing attacks.

Fortunately, Twilio's Lookup API can detect carriers and we can use this to filter out known bad actors before sending an SMS verification.

Here's a quick snippet of an example block list:

const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = require("twilio")(accountSid, authToken);

// hard coded for demo purposes only
const block = ["12301", "12302"];

client.lookups
 .phoneNumbers("+15108675310")
 .fetch({type: ["carrier"]})
 .then((resp) => {
   const mccmnc = resp.carrier.mobile_country_code + resp.carrier.mobile_network_code
   if (block.includes(mccmnc)) {
     // block or add additional checks
     console.log("blocked!");
   } else {
     // proceed with sending one time passcode
     console.log("allowed!");
   }
 });

The rest of the post will cover building this solution with the Twilio Lookup API.

How to define a carrier in code: MCC and MNC

The mobile country code (MCC) and mobile network code (MNC) combination is globally unique and is used to identify carriers worldwide. Note: MCC and MNC are not available for landline numbers.

This data is returned in a carrier Lookup response when available:

{
  "caller_name": null,
  "carrier": {
    "error_code": null,
    "mobile_country_code": "310",
    "mobile_network_code": "456",
    "name": "verizon",
    "type": "mobile"
  },
  "country_code": "US",
  "national_format": "(510) 867-5310",
  "phone_number": "+15108675310",
  "add_ons": null,
  "url": "https://lookups.twilio.com/v1/PhoneNumbers/+15108675310"
}

An attacker will often send requests to a range of sequential numbers using the same prefix, so be on the lookout for un-checked verification traffic coming from the same prefix. If you choose to block prefixes it's worth unblocking after some time has passed in order to re-allow legitimate traffic.

You can find a list of all MCC-MNCs at this website: https://www.mcc-mnc.com/ and a list of mobile telephone prefixes here.

Prerequisites for building a carrier detection list

To code along with this post you'll need to:

Step 1: Sign up for or sign into your Twilio account

Step 2: Install Node JS https://nodejs.org/en/download

Step 3: Install Twilio CLI (learn more)

npm install -g twilio-cli

Step 4: Install the Serverless CLI plugin

twilio plugins:install @twilio-labs/plugin-serverless@1.9.0

Step 5: Login to the CLI with your Twilio account credentials

twilio login

Download the Lookup starter template

Using the CLI, clone the international telephone input template from the Twilio code exchange:

twilio serverless:init lookup-block-list --template=international-telephone-input && cd lookup-block-list

Open up the .env file and make sure your Twilio Account Credentials (ACCOUNT_SID and AUTH_TOKEN) have been populated, you can find your credentials in the Twilio Console. You can start the app by running:

twilio serverless:start

Open http://localhost:3000/index.html in a browser; you should be able to input your phone number and see it in E.164 format:

phone number in e.164 format

The application already does a really handy thing by accepting international formatted numbers and converting them to the standard E.164 format. The Lookup API then validates whether the number is valid or not. If you try inputting just 12345 or any other invalid phone number you'll get an error.

Add a block list to your sign-up form

Avoid hard-coding these values in a production environment. We recommend loading the list from external storage, like a configuration file or database, so that it is easier to update the list without changing the code itself.

To add a block list, open up the functions/lookup.js file and add the following line after const client = …:

const block = ["12301", "12302"];

This list is using mobile country codes (MCC) and mobile network codes (MNC) to identify carriers, which the Lookup API also uses. Our list is fictional, but you can determine MCC-MNC combinations with this site. In order to segment your verification by different MCC+MNCs, start tracking these details so you have more insights around which carriers you can trust more or less.

If you look at the rest of the function, you might notice that we're not actually using the response from the Lookup API. To make use of the response and grab the carrier that's returned, replace the 5 line block of code that starts with response.setStatusCode(200); with:

const mccmnc = resp.carrier.mobile_country_code + resp.carrier.mobile_network_code
if (block.includes(mccmnc)) {
 response.setStatusCode(401);
 response.setBody({
   success: false,
   error: "Carrier not allowed.",
 });
 return callback(null, response);
} else {
 response.setStatusCode(200);
 response.setBody({
   success: true,
 });
 return callback(null, response);
}

Finally, head over to assets/index.html and update line 73 to report the function's error message:

error.innerHTML = json.error;

Make sure the project is running with twilio serverless:start, head over to http://localhost:3000/index.html and test it out! Then try adding your mobile number MCC-MNC combination to the block list to see the error message "Carrier not allowed."

Alternatives to blocking carriers

Blocking an entire carrier does involve the risk of blocking legitimate traffic, so you could use the Lookup API response to detect riskier numbers and add protections like reCAPTCHAs to prevent bots.

You can also block or allow verifications from certain countries with a similar method described in this blog post.

You could also use the WhatsApp channel instead of SMS to send verification codes (coming soon to the Verify API).

What to do if you suspect fraud on your account

You can email fraud@twilio.com if you are facing messaging abuse on the Authy or Verify APIs. Please include the following details in your message:

Account SID:
Product Type (Authy or Verify):
Date/time Range:
To/Recipient Country:
Workspace SID:
Description of Activity:

Other uses for the Lookup API

You can also use the Lookup API to allow or detect certain countries, another way to prevent fraud and decrease the surface area of your application.

Lookup can also be used to detect line type to determine mobile vs. landline vs. VoIP numbers.

Of course, once you've implemented Lookup you'll want to Verify phone numbers using Twilio's Verify API. Here are some more resources for account security that you might enjoy:

I can't wait to see what you build and secure with Twilio!