Skip to content

Entity risk score

LogMan.io uses two related risk score concepts:

Concept Where Meaning
Detection risk score event.risk_score on complex lane events Numeric score of one detection after correlation rules and lookups (see Risk scoring in Correlator)
Entity risk score risk_score on the asset row in Mongo / HTTP API Current risk of the principal (user, host, service), decaying when no new detections arrive

This page documents the entity risk score maintained by LogMan.io Assets (lmio-assets).

Input: complex lane events

ComplexAssetsPipeline subscribes to each tenant complex event lane declaration (/EventLanes/<tenant>/complex.yaml, type lmio/event-lane-complex). The Kafka topic defaults to events.<tenant>.complex unless overridden in the lane YAML.

For each event that contains the schema risk score field (define.risk_score, default event.risk_score) and at least one principal (host.id, user.id, or service.id from the schema mapping), the service records a sample:

  • Contribution: parsed detection risk value (positive numbers only)
  • Event time: Unix ms from the schema principal datetime field (define.principal_datetime, e.g. @timestamp)

Samples are buffered and flushed to Mongo in event time order (same batching knobs as activity: complex_mongo_batch_max, complex_mongo_batch_max_age).

Merged or deleted asset _ids are ignored (shared suppress cache with activity processing).

Decay model

The stored entity score is a time decayed weighted average of detection event.risk_score values. Recent detections matter more; old ones fade but still influence the average until they decay away.

Internal Mongo accumulators:

  • risk_score_sum (S): weighted sum of detection values
  • risk_score_weight (W): effective sample weight
  • risk_score: round(S / W) exposed in the API

Between updates, both S and W decay with half life (default 24h):

S ← S × decay(Δt)
W ← W × decay(Δt)

When a detection with value c arrives at event time t:

S ← S × decay(Δt) + c
W ← W × decay(Δt) + 1
score = S / W
Symbol Meaning
c event.risk_score on the complex lane detection
Δt Elapsed time since risk_score_at → event time
decay(Δt) 0.5 ** (Δt_hours / half_life_hours)

Why not a sum? Ten low detections over a week should not stack to an extreme entity score. The average moves toward new c values; stale history loses weight exponentially.

Example: score was 80 (one detection). A new detection c = 20 arrives immediately: S = 80 + 20, W = 2, score 50 (not 100). After 24h silence, both S and W halve, score stays 50. Then c = 60: score becomes 55.

Mongo stores:

  • risk_score: rounded average (round(S / W))
  • risk_score_sum / risk_score_weight: internal accumulators (not in public JSON)
  • risk_score_at: Unix ms of the last update clock (not exposed in public JSON)

Scores that decay below risk_score_decay_clear_below (default 0.5) are cleared from API responses and removed on the passive decay job.

Late arriving events

If an event timestamp is before risk_score_at, its value is blended into the average, but risk_score_at is not moved backward.

Passive decay job

On Application.tick/600! (same cadence as stale asset alerting), the service persists passive decay for all assets with risk_score > 0 so list sort (srisk_score) stays aligned with the model.

Between ticks, GET, list, and export still apply decay at read time so the API shows the effective score now.

Per asset risk score weight (lookup API)

The HTTP API exposes /risk-score-weight endpoints to read, set, or clear an optional override in LogMan.io Watcher lookups (hostid2riskscore, userid2riskscore, serviceid2riskscore). The lookup key is the asset title (principal id); the value field is risk.score (0..100).

This is separate from the decay merge logic: entity score still grows from event.risk_score on consumed complex events. Use the weight API when your deployment wires these lookups into detection scoring or analyst workflows.

Webui: stored field vs chart

In lmio_asset_webui asset detail, two views are intentional:

View What it shows
risk_score in list / sidebar Entity state now (decayed score)
Risk score line chart Detection activity over time: max(risk_field) per histogram bucket over complex lane events only (event.dataset = complex), single series (no split by rule.id)

The chart answers: “What was the peak detection risk score for this principal in each time window?”

The stored field answers: “How risky is this entity right now, accounting for decay?”

Configuration

[assets] key Default Description
risk_score_decay_half_life 24h Half life for exponential decay (ASAB duration syntax)
risk_score_decay_clear_below 0.5 Clear score when decayed value falls below this
complex_mongo_batch_max 100 Buffered detections before Mongo flush
complex_mongo_batch_max_age 60 Max seconds before partial risk buffer flush

See Configuration for the full [assets] section and service dependencies.