SMS Artificially Inflated Traffic

The Nussknacker Blog
10 min readApr 16, 2024


by Łukasz Ciołecki

Interconnect fraud, as I explained in my previous blog post, thrives on the generation of artificial traffic that is cleverly designed to mimic legitimate communications activity. The fraudsters behind these schemes easily exploit the interconnected nature of global telecommunications networks, orchestrating elaborate ruses that result in significant financial losses for operators. According to the GLF 2023 Fraud Report, around 50% of telecoms operators have reported a significant financial impact from Artificially Inflated Traffic (AIT), also known as a SPAM SMS. And from their perspective, it’s the most financially impactful fraud category, as they incur costs for traffic that is either spoofed or not authentic. That’s why today I’d like to take a closer look at SMS in AIT and show you some of the solutions in Nussknacker to deal with this type of fraud.

The Story…

The private unknown company registers mobile virtual network operator (MVNO) B.V1 in the telecom operator B. At this point it should be noted that telecom operators are obliged by law to allow the creation of virtual operators. On the other hand, why shouldn’t they? It is always about business and operators want to have an additional source of revenue. As a result, B.V1 receives a range of MSISDN numbers; for instance, between +48 666 000 000 and +48 666110000, they get 10,000 numbers. This virtual operator B.V1 is then able somehow (by buying prepaid, stealing, cloning, etc) to get its hands on , let’s say, 1,000 SIM cards from telecom operator A. This attacker starts automatically/robotically sending thousands, even millions of SMS from network operator A to its own MSISDN numbers registered with operator B’s network. Often these numbers are premium numbers, which means that the rate for sending SMS to them is significantly higher.

You might at this point ask the question: where is the fraud? And you’d have a point. After all, VNO B.V1 pays the bill for the SMS sent. And yet the situation is a little more complicated than you might think. Telecom operators prepare their offers on the basis of statistics. So the final price of an SMS or MMS for the end customer is always the average price. In the age of ubiquitous Internet access, telecoms often offer free SMS/MMS as a part of a prepaid package. Therefore, it might be the case that fraudster B.V1 pays significantly less or nothing to Operator A for sending the messages (because he sends SMS from a prepaid offer where messages are free or low cost, or he sends SMS from stolen / cloned cards) than he receives settlement from Operator B for handling the connections.

In the end, Operator A is obliged to pay Operator B a fee for handling the SMS communication.This rate/fee is known as the Interconnect. You can read more about telecom settlements in my last blog post about telecom frauds. So, the Operator A is paying a bill for millions of EUR for fake traffic from its network. Of course, we can blame Operator B, but how fair is this? After all, operator B isn’t aware about the whole situation as well as the victim operator A. Clarification procedures between operators take an awfully long time, because, to use our example,VNO B.V1 can create another sub-operator (which can create another dodgy sub-operator), which makes it very difficult to get to the fraudster. According to the law, Operator A is obliged to pay billing in a certain time, while our virtual fraudster operator disappears after receiving the money.

How to Detect & Handle SPAM SMS Fraud

Using Nussknacker’s robust real-time processing capabilities, we can build complex decision diagrams that analyse patterns, behaviours and anomalies that indicate SPAM SMS Fraud. This approach allows us to quickly identify potential threats and take proactive action to prevent fraud before it happens. Let’s look at some possible solutions.

Source SMSC data analysis in real-time

What is SMSC and how does it work?

In the world of telecommunications, the Short Message Service Center (SMSC) plays a highly important role as the backbone of SMS (Short Message Service) communication. It acts as an intermediary between senders and recipients, ensuring that text messages are delivered accurately and efficiently. When you send a text message, it first reaches an SMSC, which then processes and delivers it to the intended recipient’s device. If the recipient is unavailable or their device is switched off, the SMSC stores the message and attempts to deliver it at a later time. This mechanism ensures the reliability and timeliness of SMS, a service that has become indispensable to the telecommunications industry for personal communications, marketing, alerts and more. In addition to handling individual messages, SMSCs are critical to a wide range of applications that rely on SMS for authentication, notifications and automated responses, demonstrating their integral role in the seamless operation of mobile networks. Here you can find a short video about how SMSC works.

Call Data Record Source

Let’s assume that the Call Data Records received by Nu from SMSC have the following structure:

smsc_id — unique identifier of message, type string

smsc_class — message class, type string

record_type — message type, type int, options:

  • 1 — SMO, outgoing message
  • 2 — SMT, terminated/handled message

message_status — message status, type int, options:

  • 1 — NROUTE
  • 3 — EXPIRED
  • 4 — DELETED
  • 6 — ACCEPTED
  • 7 — UNKNOWN
  • 8 — REJECTED

msisdn_a — sender’s MSISDN, type string

msisdn_b — receiver’s MSISDN, type string

ton_a_number — sender’s type of number, type int

ton_b_number — receiver’s type of number, type int

text_length — message length, type long

imsi_a — sender’s international mobile subscriber id, type string

imsi_b — receiver’s international mobile subscriber id, type string

entry_date — timestamp of creating message, type long

delivery_date — timestamp of delivery message, type long

delivery_attempts — number of delivery tries, type long

source_smsc — sender’s SMSC MSISDN, type string

destination_smsc — receiver’s SMSC MSISDN, type string

source_ei_id — source type of traffic, type string

destination_ei_id — destination type of traffic, type string

Typically this is implemented as an event stream. The first node in the diagram (“source”) is responsible for reading CDRs from the stream. The technical details of this are completely hidden from the person creating the diagram — more on this can be found here. Once the CDR has been read, its content is available in the #input variable. Read more about variables here.

International outgoing & delivered SMS

We have to ask ourselves the question: what kind of SMSC data are potential SPAM SMS AIT frauds?

First we’re looking for:

  • Only outgoing SMS => #input.record_type == 1
  • Only delivered SMS => #input.message_status == 2
  • Only sender’s MSISDN in International type of number, e.g. +48666333666 => #input.ton_a_number == 1

Known cases — whitelisting

Of course, there are corner cases like in every business. This is the place where the whitelist comes in! In Nussknacker, you can achieve this pattern by declaring decision tables with a list of special users (it’s similar to Excel).

In this situation, we define three specific customers who are known to our business and we are sure that they are allowed to send a higher volume of SMS. We assign these three users in the variable white_list, which is represented as a list of records with fields: name and msisdn.

Once we have declared the whitelist, we need to check that the sender of the incoming SMS record is on this list:

#white_list.?[#this.msisdn == #input.msisdn_a].isEmpty

The above expression checks if the sender (#input.msisdn_a) is on a white list and returns true or false. Check out here to understand the syntax of this expression.

Prepaid accounts

Next, we want to continue only with prepaid MSISDN. Unfortunately, the record from the SMSC doesn’t contain any information about the client and its account type. So we have to enrich our incoming record with client information stored in an external system. And here, fortunately, Nussknacker allows us to do this in a few ways:

In this example, we use the OpenAPI enrichment to retrieve the sender’s account details. Nussknacker has automatically generated this enricher component and made it available in the component palette. You can find more about enrichers here.

After retrieving the user data from the external service using the incoming sender MSISDN, and storing this information in the client variable we need to check the account type.

Now we can be sure that only records with account_type equal to prepaid will be processed.

Performance tip

The order of filters and operations isn’t random. There is no need to fetch user data, e.g. for undelivered messages, because the telecoms only pay for handled messages. First, we should perform operations to exclude events without using external services, because calling external services is heavy. Remember that clients send millions of messages during the day, and making unnecessary calls to external services for every SMSC message event can kill these services.

Final AIT SMS Verification

OK, so we are almost done, but how do we check that someone is sending too many SMS? In this situation, we assume that sending more than 10,000 SMS in a period of time to the shortlist of numbers could indicate fraud.

This process is easier than it might at first appear. So, for a sender (groupBy: #input.msisdn_a), we want to check in a certain time window (windowLength: 8h) that it’s sending a large number of messages to a finite number of recipients. We build the aggregation in the defined time window, which contains:

  • count: number of messages, type long
  • uniqueNumbers: set of unique recipients, msisdn_b. Keeping unique numbers in the set for each msisdn_a may not be an optimal solution, for better performance we can use #AGG.approxCardinality, see here for more information.

This aggregator is updated after each event and stored in the variable aggr, containing the following fields: count, uniqueNumber. After every eight hours (time window), the aggregator is reset and refilled.

Finally! We check whether the sender sent more than 10,000 SMS in the last 8 hours with a rate of unique recipients (#input.msisdn_b) less than or equal to 0.2 (this means that he mostly sends messages to the same MSISDNs). In the case that he has sent more than 10,000 SMS with high uniqueness ratio, we assume it could be a potential fraud, but we don’t want to take any action, just log this message after a detailed manual verification.


Ultimately, we want to act in an automated way when we are sure that we have detected fraud. Should this be the case, we need to do three things:


If we are sure of the fraud, we want to block the fraudster and stop sending SMS, so we call an external service to block MSISDN.

Inform customer

It’s good practice to inform our customer about the whole situation. After all, perhaps we’ve made a mistake and our algorithm has a bug? Therefore we send an SMS to the customer with information about the blocking.

Log information for analysis

It is also important to record the executed action: blocking/potential fraud for further analysis. In our example, we write a message to Kafka’s topic: ‘monitor’, then this message will be forwarded to Kibana where business people will be able to do some magic analysis.


Our aim was to detect and block prepaid SPAM SMS scammers, and we succeeded in doing this. Of course you can say that: Hey Lucas, this is such a simple solution and scammers will surely get around your security! And you’re right! This solution is just an example, it depends on you and how sophisticated the AIT detection algorithm you will prepare for it:

  • Will you include geolocalisation
  • Will you include special information about your customer
  • The sky’s the limit… :)

And you know what the best part is? You don’t need developers at all to change it, finally the work can be done by business experts without any IT guys! :)

I almost forgot, remember that Nussknacker is OpenSource and you can find us on Github!