DEV Community

Butterfly88
Butterfly88

Posted on

What happens when a bot gets past your CAPTCHA?

CAPTCHA is good at stopping automated registrations. But what happens when the registration succeeds?

That was the problem I ran into on a WordPress community I run.

We started seeing new accounts that looked seemingly normal during registration. The usual registration protections did their job. There was no obvious reason to block the account.

The suspicious activity started later.

The problem moved inside the community

After creating an account, some of these users started sending private messages to other members. Sometimes in obvious spam waves and other times using more refined scam methods.

With the latter, the first message looked somewhat out of the ordinary, but otherwise seemingly harmless. After a short conversation, they tried to move the conversation to TeleGram or another messaging service. Some of the patterns looked like dating scams. Others involved cryptocurrency.

What made this interesting from a technical point of view was that the account itself had already passed every bot protection check because it had already passed registration. Once logged in, most anti-bot solutions are no longer in effect.

From WordPress's point of view, it was simply an authenticated user sending a message. That made me realize that registration protection and (private) messaging protection are two different problems.

Why CAPTCHA could not solve this

A CAPTCHA can help answer:

Is this registration likely to be automated?

It does not answer:

Is this newly registered account behaving like an automated spam account?

And it certainly does not answer:

Is this person using private messaging to approach dozens of members with essentially the same message?

Those signals only become visible after the account has entered the community and I started getting reports from my users. Which is when I started looking at the messaging layer instead.

What I started looking for

One of the first things I noticed was that simple message counters were not enough. I already had these in place, but the spammy accounts would patiently wait for the message interval to reset. They were also able to alternate between messages.

That meant I needed to look at several signals together.

For example:

  • How recently the account was created?
  • Were there repeated or very similar messages?
  • Are there any email addresses and/or phone numbers in messages?
  • Are there any links and messaging-service references?
  • Are there any signs of automated clients or any unusual combinations of browser and client information?
  • Had the account had enough time to establish the normal activity you would expect from a new member?

None of these signals is necessarily enough on its own, but together they can tell a very different story.

Building the protection

Like many others, the community I run uses BuddyPress and Better Messages for private messaging. After fruitless searches around the web for a solution, I eventually built a protection system as an addon rather than trying to replace the messaging system. Being very happy with the solution for myself, and realizing that a lot of other people I discovered during my searches were facing the same problem, I realized I wanted to share the benefit with the larger community.

The result is a free, open-source WordPress plugin called Anti-Spam Guard for Better Messages.

It can apply different checks at the messaging layer, including new-account limits, duplicate-message detection, contact-detail and link detection, automation checks and safety warnings. There is also a "Log Only" mode.

I built that specifically because I really needed it to fine-tune the settings to my specific needs, before interrupting any normal user behavior. And of course, every website has different needs.

Logging first turned out to be important, because security rules can have false positives and other nasty side effects. Being able to see what would have been blocked before actually blocking anything makes it much easier to tune the rules for a real community.

I realized there is an undercovered part of spam protection

The bigger lesson for me was where the problem actually existed. There are so much plugins and other tools for battling bots and spam, but they only cover the basics, such ungated content and comment forms. But when you run gated content and use private messaging tools, there is less to find.

That distinction is easy to miss when you think of spam protection as a single feature. A site can have a good CAPTCHA, rate limiting and registration checks and still have a problem with what newly created accounts do afterwards. Accounts that can even be created by a normal human, only for automation to take over later.

So once a suspicious account gets through the front door, the private messaging system becomes the interesting attack surface, because it was not protected in the same way as the standard forms.

A second layer of protection

I don't think this means every new account should be treated as malicious, because that would make a community rather unpleasant to use. And user experience is so, so important to me.

So... the more useful approach is to apply additional checks where they make sense and make them proportional to the risk.

A new account sending its first private message is different from a long-standing member having a normal conversation.

That is the gap I was trying to address.

If you run a WordPress community with private messaging, I'd be interested to hear whether you have run into the same problem: registration spam getting through, followed by suspicious activity inside the messaging system.

Top comments (1)

Collapse
 
blobdole profile image
Doug

No matter how hard you try to block bot accounts at the door, they can always have a human log them in and pass any number of human checks for a few pennies. I have found that a weighted threshold setup for identifying spam accounts before they spam (or at worst right as they start) works really well.

Fake numbers incoming:

  • 80% of spam accounts were created in the last month compared to only 15% of real users so if true, +10 points.
  • 75% of spam accounts have no bio information at all compared to only 25% of real users so if true +7 points.
  • 65% of spam accounts are connecting through known forwarded or foreign IP's compared to only 40% of real users so if true +2 points.
  • 95% of spam accounts do not post a non-spam message in any channel within 5 minutes of joining compared to 60% of real users so if true +3 points.
  • 50% of spam accounts first messages will be posted within a very tight time frame and into every channel they have access to compared to 2% of real users so if true +25 points.

The chance that any one of those things has a false positive is too high to use, but the combination will work well. Keep a running point total and if any account passes a given total value, immediate mute and deletion of their previous 24 hours of posts.