- Waffle's yttrx blog/
- Posts/
- catching up on the anti-abuse stack: welcomebot, abuse-bot, and the new signup scrutiny/
catching up on the anti-abuse stack: welcomebot, abuse-bot, and the new signup scrutiny
I’ve been heads-down on anti-abuse work for yttrx lately, and figured this journal is a better home for it than my own memory. Here’s roughly where things stand.
The hooks server: welcome-bot + abuse-bot #
I started with a FastAPI webhook server (yttrx-welcomebot) running on admin, sitting behind an admin site. Mastodon fires an admin webhook on account.created, account.approved, and report.created, and this service allows me to run some custom logic to decide how to handle these actions.
Welcome-bot is the simple half: it DMs every new local signup a welcome message, using its own bot account and token. It listens to both account.created and account.approved because yttrx (sometimes) requires approval on signups, and I wanted the welcome to fire regardless of whether that gate is on. Everything’s deduped in sqlite so nobody gets welcomed twice.
When I first started working with yttrx, a lot of new users didn’t know how mastodon worked, and I wanted them to get directions to a soft landing spot (the welcome website) where they could learn how to find content, follow, etc.
Abuse-bot is the more interesting one. On a new report against a local, non-staff account, it:
- Classifies the target by their posting history — young account, dormant account, no posts at all, or just an active account getting reported.
- Counts distinct reporters against them, not raw report count, so one person filing five reports doesn’t do anything a single report wouldn’t.
- Silences the account (reversibly — never suspend) once distinct reporters cross a threshold that’s lower for young/dormant/no-post accounts than for accounts with an established posting history.
- Leaves the report open for a human to review, and DMs both a moderator and the affected user (with a link to the appeals page).
Staff are never auto-actioned — there’s an explicit allowlist plus a check against Mastodon’s own role field. And there’s a dry-run mode so any of this can be paused without touching config that isn’t meant to be touched (the .env on that box holds live tokens, so redeploys are code-only, never blow away the env file).
Two new signals at the gate #
The stuff I actually wanted to write about: two new pieces of signup scrutiny, both built to slot into the same webhook flow.
IP reputation. Every signup already carries the account’s IP for free, so I added an RDAP lookup that classifies it as datacenter/hosting, mobile, or residential. A flagged (datacenter) signup gets its welcome held until a human approves the account, gets the IP registered as an Admin::IpBlock so Mastodon remembers it, and needs a much lower reporter count to get silenced later if it ever gets reported. Still reversible, still human-reviewed — just more cautious about signups coming from hosting ranges that have no business creating a personal Mastodon account.
Disposable/high-risk email domains. Similar idea, different signal: check the signup’s email domain (never the full address) against check-mail.org, which flags disposable providers and scores domain risk. I shipped this dry-run first like everything else, then today re-minted the abuse bot’s token with the extra scope it needed and flipped it live. Now a flagged signup gets its email domain registered as a Mastodon Admin::EmailDomainBlock, and — this is the one place I let it go further than “silence” — a report against an account with a high-risk email domain auto-suspends on the first report and blocks the domain, instead of waiting for multiple reporters like the normal flow.
That last bit was a deliberate exception to my usual “reversible first” rule. A disposable email plus an actual report is a strong enough combined signal that I was comfortable with a harder action there.
Why bother with all this for a small instance #
yttrx is not big. But small instances get hit by the same automated signup spam and drive-by garbage as anywhere else, just less visibly, so the cost of not having this stuff is a slow trickle of junk accounts and the occasional brigading report rather than one dramatic incident. Building it in tiers — welcome, then reactive report handling, then proactive signup scrutiny — has let me roll each piece out dry-run first and actually trust it before I let it act on its own.
God I hate spammers, but I really want people to have servers to land on when they’re joining the fediverse.