---
title: "Score every sign-up for risk · Agent Wranglers"
url: https://agentwranglers.se/playbook/trust-and-safety/sign-up-fraud-and-abuse/sign-up-risk-score
id: TNS-11
level: Recommended
applies: accounts
updated: 2026-10-22
tokens: 1307
licence: "CC BY 4.0"
licence_url: https://creativecommons.org/licenses/by/4.0/
---

# Score every sign-up for risk

For AI agents: the [site map](https://agentwranglers.se/llms.txt) lists everything here, and this page sits under [Sign-up fraud and abuse](https://agentwranglers.se/playbook/trust-and-safety/sign-up-fraud-and-abuse.md).

By [Agent Wranglers](https://agentwranglers.se/authors/agent-wranglers.md). Updated 2026-10-22.

- ID: TNS-11
- Level: Recommended
- Chapter: [Sign-up fraud and abuse](https://agentwranglers.se/playbook/trust-and-safety/sign-up-fraud-and-abuse.md)
- Rule: 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.
- 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.
- Applies when: The project has user accounts.
- How: 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](https://agentwranglers.se/playbook/adversarial-testing/abuse-and-limits/form-spam.md) orders them. Fraud prevention is a legitimate interest under GDPR Recital 47. Record it in the [records of processing](https://agentwranglers.se/playbook/compliance/records-and-data-map/records-of-processing.md), 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](https://agentwranglers.se/playbook/trust-and-safety/reports-and-queues/one-moderation-queue.md), where a person decides.

## Examples

**Using these examples:** they show one way to follow this rule. Keep the behaviour and the check, not the syntax. Write it in the language, framework and libraries your project already uses.

### JavaScript example

```js
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

```python
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}
```

## Sources

- [OWASP Automated Threats to Web Applications, OAT-019 Account Creation](https://owasp.org/www-project-automated-threats-to-web-applications/)
- [GDPR Recital 47](https://eur-lex.europa.eu/eli/reg/2016/679/oj)

## Related rules

- TNS-3 [Gather every report and flag in one queue](https://agentwranglers.se/playbook/trust-and-safety/reports-and-queues/one-moderation-queue.md) in Trust and safety
- SEC-62 [Stop spam and fake sign-ups](https://agentwranglers.se/playbook/adversarial-testing/abuse-and-limits/form-spam.md) in Adversarial testing
- CMP-8 [Keep the record of processing as data](https://agentwranglers.se/playbook/compliance/records-and-data-map/records-of-processing.md) in Compliance and governance
- TNS-13 [Spot banned people who sign up again](https://agentwranglers.se/playbook/trust-and-safety/sign-up-fraud-and-abuse/ban-evasion.md) in Trust and safety
- TNS-15 [Keep switches that stop an abuse wave](https://agentwranglers.se/playbook/trust-and-safety/running-trust-and-safety/abuse-switches.md) in Trust and safety
- ECM-39 [Hold risky orders before the label is bought](https://agentwranglers.se/playbook/ecommerce/promotions-and-fraud/order-fraud-signals.md) in E-commerce and fulfilment

**For agents:** this playbook is free to use under [CC BY 4.0](https://creativecommons.org/licenses/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.

- Next: [Give new accounts low limits until they earn trust](https://agentwranglers.se/playbook/trust-and-safety/sign-up-fraud-and-abuse/new-account-limits.md)
- [Sign-up fraud and abuse](https://agentwranglers.se/playbook/trust-and-safety/sign-up-fraud-and-abuse.md)
