SOC early warning
When the curve crosses 0.75 before anything has happened, triage becomes something you schedule rather than something that wakes you up.
Every 30 seconds NIDRA turns each host's traffic into 45 numbers. It has learned how those numbers move, so it can run them forward three minutes and say where the host is heading. In the Wednesday replay that was 90 seconds of warning before the scan became an intrusion.
Built in the open, on public data
How we check
Two baselines run alongside it: persistence, and the same model with the context shuffled.
See the numbersA compromise takes minutes, not milliseconds
Recon, then a foothold, then movement sideways. Each step changes how the machine behaves, and it all happens before anything is taken.
What the model actually does
Every 30 seconds it reads each host's traffic into a state vector, runs that state forward, and shows which features moved the projected risk. All of it on CPU.
The output is a number of seconds, not a verdict on something that already happened.
OBSERVE
We capture live network flows, aggregate them per host in 30-second windows, and convert the activity into a 45-dimensional state vector.
Why per-host, not per-flow?
A compromise unfolds over time on a machine — scanning, probing, foothold, lateral movement, exfiltration. Per-flow data shows only a slice. Per-host sequences reveal the trajectory.
Model input: 45-dimensional host state vector
The 45 features capture flow statistics, temporal patterns and protocol behaviours, giving the model a complete picture of what the host is doing in that 30-second window.
What-if simulation
The model can also simulate alternative futures (e.g., “what if the host starts scanning?”) to show how projected risk changes. This is a model-internal what-if — a question about the model, not the network.
Runs offline. No API key, no cloud round trip.
Drop a PCAP or CSV of flow records
CIC-IDS2017 slices work out of the box
NIDRA Predictor
One interface with three methods: forecast, counterfactual, explain. It loads once and scores in under 300 ms on CPU, then hands back a risk curve, a predicted stage, and the flows behind them. Counterfactuals here are model-internal what-ifs.
Four steps. About 1000 sampled futures per host, recomputed every 30 seconds.
Traffic becomes state:
What the model learns:
Roll the future forward:
Every forecast comes with its reasons:
6-stage attack lifecycle
Four views on the same forecast: the curve, the stage, the reasons behind it, and the numbers we are judged on.
CIC-IDS2017 · tshark · PyTorch
The risk curve per host, and the seconds of warning on it.
| Host | Risk | Predicted stage | Lead time |
|---|---|---|---|
| 192.168.10.14 | 0.82 | lateral | 90 s |
| 192.168.10.51 | 0.77 | c2 | 60 s |
| 192.168.10.8 | 0.64 | initial_access | — |
| 192.168.10.25 | 0.41 | recon | — |
| 192.168.10.3 | 0.18 | benign | — |
Console mock with illustrative values — the live view ships with the replay demo.
Can the model beat “the next window looks like this one”?
If persistence keeps up, the model is not earning its complexity. That result gets published and diagnosed rather than buried.
See metricsHeads train on observed states only, then freeze. Nothing forward-looking can come from anywhere else.
Nothing after time t reaches the input. Normalisation is fitted on the training period and serialised.
Pinned seeds, one config file, and the metrics committed next to the code.