Repository navigation
Incidents
prohori incidents parses a log file, runs the detection rules and groups related alerts into
incidents: one per attack, with a score you can read line by line.
uv run prohori incidents samples/logs/account-takeover.jsonl # one table per incident
uv run prohori incidents samples/logs/auth.log --year 2026 -f json > incidents.jsonl
uv run prohori incidents my.log --online # real IP lookups
uv run prohori incidents my.log --no-enrich --gap 1hIt takes the same parser and rule options as prohori detect. Exit codes: 0 no incidents, 3
incidents found (--exit-zero gives 0), 1 nothing could be parsed or a rule file is invalid,
2 invalid usage.
| Part | What it tells you |
|---|---|
| Score and severity | 0-100 points, each with a reason; severity never below the worst alert |
| Confidence | high, medium or low, from how well the evidence corroborates itself |
| Entities | The IPs, accounts, requests and sessions involved |
| Timeline | Every matched event and alert, in order |
| Indicators | IP addresses with their enrichment, and user agents |
| ATT&CK | Tactics and techniques from the rules, checked against Enterprise ATT&CK v20.0 |
| Recommended actions | From the rules' runbooks; Prohori never acts by itself |
| Limitations | What weakens the evidence, such as a single log source or demo enrichment data |
| Provenance | Input file SHA-256, rules fired with their file hashes, versions |
Alerts join one incident when they share an IP address, account, request id or session id
and are at most 30 minutes apart (--gap). Prohori also follows the account behind an alert,
so a password-guessing burst, the sign-in that worked and an account change made afterwards from
another address end up together. The server name never groups alerts. An IP shared by more than
10 accounts (an office network, a proxy or a VPN) stops grouping alerts, and the incident says so.
| Component | Points |
|---|---|
| Most severe alert | low 10, medium 20, high 35, critical 50 |
| Each further rule | +10, at most +30 |
| A sign-in succeeded after failed attempts | +20 |
| Password, payout number, two-step verification or admin role change | +15 |
| Bad reputation of the worst IP | up to +20 |
| More IPs or accounts involved | +5 each, at most +15 |
| Sign-in from an IP new to the account | +10 |
| Sign-in with an app or client new to the account | +5 |
The total is capped at 100, shown as a negative line so the breakdown still adds up. When an account has no earlier sign-in in the log, Prohori cannot tell whether an address is new: that gives no points and a limitation instead of a guess.
Enrichment is offline by default for incidents: bundled demo data, local GeoLite2 files and
cached answers. Add --online to send public addresses to the providers you configured (see
Enrichment); at most 100 addresses are looked up per run, each once.
The full scoring table and rules are in docs/INCIDENTS.md.
Repository · Changelog · Security · MIT License
Prohori
Contributing
Reference