It looks like potentially someone is trying to validate a stolen or bought list, and then the owners of the email addresses that work are marking the confirmation emails (which they did not ask for) as spam. (At least, I can’t think of any other plausible way this would benefit the attacker.)
If possible, I would like to avoid hiding behind Cloudflare. I’m self-hosting on Fly.io, and using Postmark for transactional email, and Mailgun for newsletters.
I see in my logs POST //members/api/send-magic-link" 201, and my hunch is that someone is hitting the endpoint directly with a script.
I ended up capitulating and putting my blog behind Cloudflare, but even with bot fight mode activated, it didn’t help. However, a quick look in the actual logs showed that it was a very basic script kiddie attack, and even though the IPs seemed to change (mostly US and UK so far), they hadn’t bothered to spoof the user agent:
"user-agent":"Python/3.12 aiohttp/3.9.5"
So I added a Cloudflare Web Application Firewall (WAF) custom rule to block requests to /api/send-magic-link when the user agent “contains” Python and aiohttp.
I’m still looking for a better solution, that I can implement at the Ghost or Fly.io level, without relying on Cloudflare.