Observations about spam signups

I’m observing spam signup behaviors on Synaps Media since a while, and noticed some patterns that I wanted to share.

Spam signup requests (to /members/api/send-magic-link/ endpoint) comes from a wide range of IPs. I checked some of the popular IPs on our platform and noticed that they are mostly coming from some servers or Tor Network. Because Tor Network IPs are mostly the IP addresses of individual people and Tor Network is also used for privacy considerations in some countries, I’m not confident to block whole networks. Some server-side traffic is also can be used by VPNs. So blocking them can also affect legitimate visitors.

E-mail addresses coming with requests seem valid. They don’t bounce. I get some complaints but not that much. Even though most of them don’t convert to a member since they don’t click the link to approve confirmation link, some of them converts. I think it’s because just the fact that some people just click the links in emails without actually understanding what is it about. So members from some countries that you would not expect, can be related with those spam signup requests.

Motivation

There is a pattern that, same IPs make login requests with an email, get “No member exists with this e-mail address” response, then make a signup request for same email. This gives me the idea about the motivation behind these requests: They are using Ghost sites to a way of checking if an email address is actively used. If the owner of the email coverts to a member, then login requests sends magic link to login, instead of error message. So the attacker can confirm that that email address owner is actively using that address, -and even more- is eager to click links that they should not. (So great targets for phishing attacks)

Actions

These signup confirmation emails increases the risk to be flagged as spammer. It’s a risk for our domains and mailing services.

If the motivation behind this attack is collecting a list of validated emails for phishing, then I think there is a simple way of preventing this: Using “One time codes” over “Magic Link”. One time codes already replaced magic links for member login flow. I think it’s also needed (maybe even more) for signup flow. Using one time code, will prevent having those fake/accidental members completely, since visitor should complete the flow in the same window they started.

Edit: I just remembered that one-time-code emails still includes magic links and a big “Signup now” button that just calls the magic link. I think still it’s more “discouraging” to click the button than the current version, but even better would be to drop magic link in login flow completely.

What do you think?

Do you also have observations and ideas about this issue? If you get fake-looking members, can you please share, with the information about your hosting provider or self-hosting?

4 Likes

I can confirm that I am seeing the exact same pattern on Magic Pages. Overall, it does remind me of the SMS gateway spam that happened last year – but this time it seems a lot more sophisticated, in the sense that whoever’s doing this knows a lot more about how Ghost works.

One idea I had was blocking known Tor exit nodes on the /members/api/send-magic-link/ endpoint. However, quite frankly…I am missing the tooling for that to do this in an efficient way that doesn’t impact real people. I might have some more ideas, but want to try them first before putting it out in public.

Another way to mitigate it is @curiositry’s way:

However, if Ghost implemented that upstream, it would just be a matter of time before they hit the new endpoint.

2 Likes

I’m not sure you linked the right post, Jannis? But you mean the one where he actually relocated the endpoint, right?

It’d be interesting if each Ghost site got its own endpoint location (or it were user-configurable). But Portal is still going to need to know where the endpoint is, and so then we’re back to ‘bots can figure it out’ pretty quickly…

2 Likes

Haa! Copied the wrong one. Fixed :smiley:

Yeah, obscurity won’t work much given that the endpoint NEEDS to be known for the frontend.

I like @muratcorlu’s one-time code suggestion.

Thinking about it again…isn’t this a classic captcha problem? Yes, captchas are solvable for bots. But their job is to just make things so expensive for them that it doesn’t pay off anymore.

Just finding the magic link endpoint and filling in the right forms…easy. But having to do proof of work every time? Well…might just not pay off anymore.

Edit: I am stupid. That wouldn’t work on the API route anyway :joy:

1 Like

One-time-code, would fix the “accidental” signups only. If the motivation of this attack is to determine if an email will convert to a member by just sending a signup confirmation email, then with one-time-code, none of them will convert to a member.

Because I see that the same IPs are also trying login flow as well, I think that’s the biggest motivation behind it. And I think using one-time-code instead of magic link, is a way better solution than putting a captcha. (Yes, I hate captchas :blush:)

1 Like

Great to see this thread, with everyone’s experience and ideas collated.

I collected the patterns I’ve seen, possible motivations, and mitigations I’ve used into a post on my blog, What’s the end game for Ghost newsletter sign-up spam?, and I agree with @muratcorlu’s observation that it could be preparation-for-phishing (I hadn’t noticed separate login attempts that precede the signups, but that makes sense).

A few thoughts:

  • My opinion of captchas: :face_vomiting:
  • Re: blocking server traffic: services like these attract the worst and the best people, and as a tech blogger, I think probably some of my smartest readers would be bycatch. It’s like Facebook deciding that Linux was “malware”. Yes, probably most malware is created using Linux. But also, probably most of Facebook is created using Linux?
  • One time codes seem like it would make Ghost less attractive of a target, but I think that it might reduce completions of the signup flow, compared to a button you can click
  • If it’s phishing preparation, witholding the information that no user with that emailt exists might help, but this would also impact real users who typed their email wrong, so it’s probably isn’t a good idea
  • Changing the endpoint has worked, but also been quite a pain. Most of the hassle has been specific to being the only person running forked code, and wouldn’t necessarily apply if endpoint-changing was built into Ghost.
    • Any firewall rules around that endpoint must be updated.
    • It will tend to quietly break integrations that hit it directly
    • If the portal and embedded signup code are changed, they won’t be delivered by a CDN, and they won’t be cached from the last time someone read a Ghost blog, and the portal.min.js is like 2MB, so this is not a trivial waste

In the short term, I think my top ideas are:

  • adding magic link endpoint customization/randomization (it might not last forever but I think it will help)
  • add an option for manually approving signups
  • or putting an email validation API step before the first email gets sent
  • integrating something like Anubis/BotStopper into Ghost, so the whole site is behind a proof-of-work captcha
4 Likes