The Autodidacts

Exploring the universe from the inside out

What’s the end game for Ghost newsletter sign-up spam?

My theory of mind is failing

Note: this post is part of #100DaysToOffload, a challenge to publish 100 posts in 365 days. These posts are generally shorter and less polished than our normal posts; expect typos and unfiltered thoughts! View more posts in this series.

If you know the enemy and know yourself, you need not fear the result of a hundred battles. If you know yourself but not the enemy, for every victory gained you will also suffer a defeat. If you know neither the enemy nor yourself, you will succumb in every battle. ― Sun Tzu, the Art of War

I think I’m somewhere between 2) and 3) in Sun Tzu’s taxonomy.

Artist's rendering of self-hosting in 2026
Artist's rendering of self-hosting in 2026

Intermittently, for years, the Ghost blog you’re reading has been barraged by attacks. There are the usual script-kiddies and vulnerability scanners looking for SQL dumps and /wp-admin (hah!). But these haven’t been a problem.

The problem has been the spam signups, which never confirm, yet hurt our email sending reputation.

The pattern

  • The addresses appear valid. They’re mostly Gmail addresses, many with a few numbers in them, but also a name. It’s not the SMS spam you hear about on the Ghost forum. There’s no discernible pattern to the email addresses, and if I just saw one I would give it a >50% probability of being legit.
  • They appear to be hitting the /send-magic-link endpoint directly rather than going through the front-end.
  • At first, the User-Agent was consistently Python (”Python/3.12 aiohttp/3.9.5”, and then later python-requests), and the originalUrl had a double slash, so it was //members/api/send-magic-link rather than /members/api/send-magic-link.
  • No consistent IP range (Cloudflare listed the IP addresses as originating from multiple countries, including the US and Germany)
  • Volume of spam is variable, from a trickle, to ~800+ signups in 24hrs
  • Whoever the addresses belong to never click to confirm the subscription
  • A few of the addresses have sent spam complaints, indicating that the addresses aren’t controlled by the spammer

Why it matters: sending reputation

Somebody is “subscribing” these addresses. Since they never confirm, they never get the newsletter. But they still get the confirm your subscription email!

And they never signed up for it, so they don’t know who these “Autodidacts” are, and a tiny percentage marks it as spam.

One time, I didn’t catch it in time, got two or three spam complaints from ~800 “subscribes”, and Postmark (our SMTP provider for transactional mail) paused all sending. Fortunately, Postmark support was understanding. But it was a huge headache.

It also hurts our sending reputation, since transactional mail comes from the same address as our newsletter. Not good!

What are the spammer’s motives?

These are the hypotheses I’ve come up with so far:

  1. The spammers are trying to validate a stolen/bought/scraped list.
    • How would this work? Maybe they expect the endpoint to balk at invalid addresses (I don’t think it actually does). Or maybe they've discovered that the endpoint's response time leaks data about the validity of the address?
  2. The spammers are trying to hack the site with a malicious payload to the endpoint
    • Seems likely! But why so many different emails?
  3. The spammers are trying to hack the recipients of the emails, and are using the site as a transport mechanism for a malicious payload.
    • But I haven’t noticed anything indicating this is the case, and it would require a 0-day in Ghost.
  4. The spammers are trying to scrape/resell our paywalled/memberwalled content
    • This would be plausible, except that the emails never confirm. Also, they could do this with one valid email, so it doesn’t explain the huge volume of signups, unless there is a huge volume of different spammers using the exact same technique. Maybe there’s some hacking course and all the students are doing their homework?
  5. The spammers are trying to promote some product with comment spam, but for some reason aren't able to reach that objective
    • Once again, there's no point in creating this many accounts (unless they were succeeding, but also getting blocked)
  6. The spammers are trying to log-in to potentially-existing accounts, and they and the rightful owners have access to the email addresses.
    • This would make sense of the sheer volume of submissions
  7. It’s some dumb mistake

If you have a theory about the spammer’s aims, please let me know in the comments. Mitigation tips also welcome.

Evasive maneuvers, Mr. Sulu

First, I put the site behind Cloudflare, even though I didn’t want to. Then I moved to an Nginx reverse proxy.

I blocked the bad user agents. This lasted for a while.

I took a shot at setting up fail2ban, but it’s a bit tricky because of the weird stack the site runs (Unofficial Ghost Alpine Docker image, but not actually running in Docker, running in Firecracker VMs on Fly.io, behind an Nginx reverse proxy).

Ghost added an integrity token requirement to the endpoint, but that didn’t fix it. They also added domain-level signup blocking, but since there’s no consistent email domain, it doesn’t help in this case. And there's already a honeypot hidden form in the portal, but they aren't going through the portal as far as I can tell.

Currently, I have moved the endpoint, since I suspect the attack is a generic Ghost blog drive-by scan-and-spam campaign. Some of the bad requests had InboxReads as the referrer, which makes me think the spammer might be scraping blog directories to compile their list of targets.

If the bots find the moved endpoint, I’ll have to add a captcha, which Ghost has considered adding, or put the site behind Anubis.

I feel like the king of a very small city with a very large army surrounding it.

Cybersecurity meme with text over a painting of the Siege of Antioch
The Siege of 2368

Long live the open web!



Further reading:

Sign up for updates

Join the newsletter for curious and thoughtful people.
No Thanks

Great! Check your inbox and click the link to confirm your subscription.