TNS-11Recommended
Score every sign-up for risk
Give each sign-up a risk score from a fixed list of signals, and act on it in three bands. Allow the low band, challenge the middle band and hold the high band for review.
How to do it
Cheap signals catch most fake accounts. Look for a disposable email domain and a hosting provider's network instead of a home or mobile one. Count sign-ups from one network or device per hour. Add an email address with no history, a name that matches a known spam pattern, and a form filled faster than a person types. Weigh each signal with a number in code, and store the score with the signals that made it. A moderator then sees why, and you can tune the weights. A challenge can be email or phone proof, or a CAPTCHA, as Stop spam and fake sign-ups orders them. Fraud prevention is a legitimate interest under GDPR Recital 47. Record it in the records of processing, and keep the signals no longer than 90 days. Never close an account on the score alone. A held sign-up goes to the moderation queue, where a person decides.
Examples
JavaScript example
const WEIGHTS = { disposableEmail: 40, hostingNetwork: 25, burstFromNetwork: 25, fastForm: 15, newEmailHistory: 10 };
const CHALLENGE_AT = 30;
const HOLD_AT = 60;
export function scoreSignUp(signals) {
const hits = Object.keys(WEIGHTS).filter(name => signals[name]);
const score = hits.reduce((sum, name) => sum + WEIGHTS[name], 0);
const band = score >= HOLD_AT ? 'hold' : score >= CHALLENGE_AT ? 'challenge' : 'allow';
return { score, band, hits };
}
Python example
WEIGHTS = {"disposable_email": 40, "hosting_network": 25, "burst_from_network": 25, "fast_form": 15, "new_email_history": 10}
CHALLENGE_AT = 30
HOLD_AT = 60
def score_sign_up(signals: dict) -> dict:
hits = [name for name in WEIGHTS if signals.get(name)]
score = sum(WEIGHTS[name] for name in hits)
band = "hold" if score >= HOLD_AT else "challenge" if score >= CHALLENGE_AT else "allow"
return {"score": score, "band": band, "hits": hits}
How to check
A unit test scores a sign-up with a disposable domain from a hosting network and gets the high band. A sign-up from a home network with a known mail provider gets the low band. Every stored score lists its signals, and a test finds no signal rows older than 90 days.
Sources
Related rules
- TNS-3 Gather every report and flag in one queue in Trust and safety
- SEC-62 Stop spam and fake sign-ups in Adversarial testing
- CMP-8 Keep the record of processing as data in Compliance and governance
- TNS-13 Spot banned people who sign up again in Trust and safety
- TNS-15 Keep switches that stop an abuse wave in Trust and safety
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/trust-and-safety/sign-up-fraud-and-abuse/sign-up-risk-score">Agent Wranglers trust and safety playbook</a>. In code you write, add a comment next to it with the same link.