Risk Scoring
This page explains how the four detection dimensions compute in parallel, merge into a 0–100 score, and how that score picks the request's rate tier.
Computation
dynamicScore starts one goroutine per dimension; each accumulates its own score, flags, and detail map, then merges under a mutex:
| Dimension | Function | Page |
|---|---|---|
| Correlation | calcBasic |
Correlation Signals |
| Geo | calcGeo |
Geo Detection |
| Behavior | calcBehavior |
Behavior Signals |
| Fingerprint | calcFingerprint |
Session and Fingerprint |
If any dimension returns an error, the whole score fails (see the error-handling boundaries in Request Lifecycle).
Merge Rule
total = sum of dimension scores
if the detail map has more than 4 keys, add 25
cap total at 100
The bonus counts detail keys, not flags: geo_high_risk and geo_hopping share the geoCountries / countries keys, so both firing counts once.
Tiers
| Field | Condition | Default threshold | Effect |
|---|---|---|---|
IsBlock |
total >= 100 |
fixed | the request gets 403 |
IsDangerous |
total >= ScoreDangerous |
80 |
RateLimitDangerous applies |
IsSuspicious |
total >= ScoreSuspicious |
50 |
RateLimitSuspicious applies |
| Normal | otherwise | - | only RateLimitNormal applies |
The score is recomputed on every request and never carries over; lasting effects come only from each signal's counters and sets in Redis.
Flags
| Flag | Dimension | Score |
|---|---|---|
session_multi_ip |
Correlation | ScoreSessionMultiIP (1× or 2×) |
ip_multi_device |
Correlation | ScoreIPMultiDevice (1× or 2×) |
device_multi_ip |
Correlation | ScoreDeviceMultiIP (1× or 2×) |
frequent_404_errors / excessive_404_errors |
Correlation | ScoreNotFound404 (1× / 2×) |
frequent_login_failures / excessive_login_failures |
Correlation | ScoreLoginFailure (1× / 2×) |
interval_request |
Behavior | ScoreIntervalRequest |
extremely_regular |
Behavior | ScoreIntervalRequest × 1.5 |
too_frequent_requests |
Behavior | ScoreFrequencyRequest |
moderate_long_connection / long_connection / extremely_long_connection |
Behavior | ScoreLongConnection (1× / 1.5× / 2×) |
fp_multi_session |
Fingerprint | ScoreFpMultiSession |
geo_high_risk |
Geo | ScoreGeoHighRisk |
geo_hopping |
Geo | ScoreGeoHopping |
geo_frequent_switching |
Geo | ScoreGeoFrequentSwitch |
rapid_geo_change |
Geo | ScoreGeoRapidChange |
Examples with Defaults
| Scenario | Triggers | Total | Result |
|---|---|---|---|
| Cookieless script, 13+ new fingerprints from one IP within an hour | ip_multi_device 2× |
40 | Normal tier |
| 7 login failures in one session | excessive_login_failures |
30 | Normal tier |
| 3 sessions on one fingerprint within a minute | fp_multi_session |
50 | Suspicious tier, limit 50 |
| All three plus a 2-hour session | four signals summing to 142 | capped at 100 | 403 |
ScoreItem and the flags are never returned from Check; to observe them, infer from Redis or change the code.