Scoring model
Veritus's score is a 0–100 integer where higher means more suspicious. It's computed by summing the weights of triggered reasons, capped at 100. The verdict (allow/review/block) is decided by comparing the score against your form's thresholds.
Score → verdict
Each form has two thresholds (default: 30 and 70):
- score ≤ allow_threshold → allow
- allow_threshold < score ≤ review_threshold → review
- score > review_threshold → block
Plus: certain "hard-block" reasons (currently IP_TOR)
force verdict=block regardless of score.
Reason codes
Here are the codes the v1 rule-based scorer can emit:
| Code | Weight | Triggers when |
|---|---|---|
| EMAIL_DISPOSABLE | 40 | Email domain in our disposable list |
| EMAIL_GIBBERISH | 20 | Local part looks random (heuristic) |
| EMAIL_NO_MX | 30 | Domain has no MX record (will bounce) |
| EMAIL_FREE_PROVIDER | 5 | Gmail/Yahoo/etc. (low signal; just context) |
| PASSWORD_BREACHED | 25 | Password found in HIBP breach corpus |
| PASSWORD_WEAK | 10 | Password matches common-weak patterns |
| IP_DATACENTRE | 20 | IP belongs to AWS, GCP, DigitalOcean, etc. |
| IP_TOR | 50 | Hard block. IP on Tor exit list |
| IP_VPN | 15 | Known VPN provider ASN |
| IP_COUNTRY_MISMATCH | 15 | Declared country ≠ IP geolocation |
| PHONE_INVALID | 25 | Phone fails E.164 parse |
| PHONE_VOIP | 15 | Number is VoIP/burner (vendor signal) |
| ADDRESS_FAKE | 20 | Address doesn't validate against postal database |
| RULE_BLOCK_MATCH RULE_ALLOW_MATCH RULE_REVIEW_MATCH | 100/0/50 | Operator rule fired (forces verdict regardless of score) |
Model version
Each scored check stores its model_version:
rules_v1— current rule-based heuristic scorerrules_v1+rule_match— same scorer, but an operator rule fired and short-circuited the pipelinelgbm_v1— future LightGBM model trained on production data (coming once we have enough labelled signups)
Found a typo or have a suggestion?
Let us know.