Incident Management
Incident Management is RhythmX's formal escalation layer. It promotes high-risk actors from the triage view into tracked, assignable incidents with full audit trails, SLA enforcement, campaign linking, and external ticket integration (Jira/ServiceNow).
Full Incident Workflow
Data Collection (continuous, 24/7)
- LogRhythm SIEM →
alarm_actorstable (alarms, rules, MITRE) - RhythmX Detection Engine →
sigma_alertstable (individual detections) - Correlation Engine →
threat_casestable (attack patterns: brute force, lateral movement, APT chain, etc.)
Risk Score Calculation (every 5 minutes — actor_cache_sync)
For every actor (user/host/IP), the system calculates a 0–100 risk score from 7 factors:
Score = Threat Cases (30%) + RhythmX Detections (20%) + Volume (10%) + Velocity (10%) + Diversity (10%) + MITRE Coverage (10%) + Recency (10%)
- Volume and Velocity combine SIEM alarms + RhythmX Sigma detections for complete event coverage
- Recency uses the freshest timestamp across all sources (SIEM alarms, Sigma alerts, threat cases)
- Diversity uses SIEM rules only (Sigma rules are already counted in RhythmX Detections)
The score and last_seen timestamp are stored in the actor_risk_summary table.
Incident Qualification (every 5 minutes — incident_sync_service)
Step 1 — Auto-close stale incidents:
For every OPEN or IN_PROGRESS incident:
- If
last_alarm_timeis older than 24 hours (configurable) AND there are no open threat cases - → Set status = CLOSED and add resolution note: "Auto-closed: no activity for 24 hours and no open threat cases."
Step 2 — Find qualifying actors:
- Path A: Has at least 1 open threat case → qualifies immediately (no time filter, no risk threshold)
- Path B: Risk score ≥ 70 → qualifies (no time filter — recency is built into the risk score itself)
- Everything else stays in the triage view (analyst can promote manually)
Step 3 — Update or Create incident:
-
If an OPEN incident already exists for this actor (same entity):
- → Update
last_alarm_timeand refreshattack_type(adds any new types, comma-separated) - → No new incident is created
- → Update
-
If no OPEN incident exists (after any closure — manual CLOSED, FALSE_POSITIVE, or auto-closed):
- → Increment sequence number (counts all previous CLOSED + FALSE_POSITIVE incidents for this actor + entity)
- → Generate new
incident_id - → Determine campaign (see Campaign Linking below)
- → Create new incident with status = OPEN
- → System state set based on risk + threat cases (MONITORING / ACTIVE / ESCALATED)
- → Incident classified by recency (ACTIVE / RECENT / HISTORICAL)
- → Attack trend initialized (STABLE)
- → Auto-push to Jira/ServiceNow after ESCALATED stability check (2 cycles, ~10 min) — skipped for HISTORICAL incidents
flowchart TD
START["<b>Sync Service Runs</b><br>Every 5 minutes"] --> STEP1["<b>Step 1: Auto-Close</b><br>OPEN/IN_PROGRESS incidents<br>where last_alarm > 24h<br>AND no open threat cases"]
STEP1 --> CLOSE["Set status = CLOSED<br>Note: Auto-closed"]
STEP1 --> STEP2["<b>Step 2: Find Actors</b><br>Path A: threat_case ≥ 1<br>Path B: risk ≥ 70 + active 24h"]
STEP2 --> CHECK{"OPEN incident<br>exists for<br>actor + entity?"}
CHECK -->|"Yes"| UPDATE["<b>Update</b><br>Refresh last_alarm<br>Refresh attack_type"]
CHECK -->|"No"| SEQ["Increment sequence<br>Generate new ID"]
SEQ --> CMP["Check for closed incident<br>within 7 days (campaign)"]
CMP --> CREATE2["<b>Create Incident</b><br>Status: OPEN"]
CREATE2 --> PUSHCHECK{"Auto-push?"}
PUSHCHECK -->|"Yes"| PUSH2["Jira / ServiceNow"]
PUSHCHECK -->|"No"| DONE["Done"]
PUSH2 --> DONE
style START fill:#4a148c,stroke:#9c27b0,color:#fff
style STEP1 fill:#37474f,stroke:#78909c,color:#fff
style CLOSE fill:#1b5e20,stroke:#66bb6a,color:#fff
style STEP2 fill:#1a237e,stroke:#534bae,color:#fff
style CHECK fill:#00695c,stroke:#4db6ac,color:#fff
style UPDATE fill:#0d47a1,stroke:#42a5f5,color:#fff
style SEQ fill:#e65100,stroke:#ff9800,color:#fff
style CMP fill:#6a1b9a,stroke:#ab47bc,color:#fff
style CREATE2 fill:#b71c1c,stroke:#ef5350,color:#fff
style PUSHCHECK fill:#00695c,stroke:#4db6ac,color:#fff
style PUSH2 fill:#1565c0,stroke:#64b5f6,color:#fff
style DONE fill:#1b5e20,stroke:#66bb6a,color:#fff
Key Rules:
- Only one open incident per actor per entity at any time
- Incidents are created directly as OPEN — there is no "NEW" status
last_alarm_timeis automatically copied fromactor_risk_summary.last_seenon every sync cycle- After any closure (manual or auto), the next qualifying activity always creates a new incident — never reopens the old one
Incident Statuses
There are four statuses. There is no separate AUTO-CLOSED status in the system.
| Status | Description | How it gets here | UI Display |
|---|---|---|---|
| OPEN | Awaiting analyst assignment | Auto-created by sync service | OPEN |
| IN_PROGRESS | Analyst actively investigating | Analyst assigns themselves | IN PROGRESS |
| CLOSED | Resolved — threat handled or inactivity timeout | Analyst closes manually OR system auto-closes after 24h | CLOSED or CLOSED (auto) |
| FALSE_POSITIVE | Benign — not a genuine threat | Analyst determines not a real threat | FALSE POSITIVE |
Important: When the system auto-closes an incident, it sets the status to CLOSED and adds the resolution note "Auto-closed: no activity for 24 hours and no open threat cases." In the UI, this displays as CLOSED (auto) for clarity — but it is the same status as a manual CLOSED.
All closure types (manual CLOSED, FALSE_POSITIVE, and auto-closed) behave identically for:
- Campaign linking
- Sequence counting
- New incident creation
- Analyst closures do not break the campaign chain
Incident Lifecycle
Status transitions during an active incident:
flowchart LR
OPEN["<b>OPEN</b>"] --> IP["<b>IN_PROGRESS</b>"]
IP --> CLOSED["<b>CLOSED</b>"]
IP --> FP["<b>FALSE_POSITIVE</b>"]
style OPEN fill:#e65100,stroke:#ff9800,color:#fff
style IP fill:#0d47a1,stroke:#42a5f5,color:#fff
style CLOSED fill:#1b5e20,stroke:#66bb6a,color:#fff
style FP fill:#6a1b9a,stroke:#ab47bc,color:#fff
- OPEN → IN_PROGRESS: Analyst assigns the incident
- IN_PROGRESS → CLOSED: Threat confirmed and remediated
- IN_PROGRESS → FALSE_POSITIVE: Determined to be benign
- OPEN → CLOSED: Auto-closed after 24h inactivity + no open threat cases
What happens after closure:
flowchart LR
CLOSED["<b>CLOSED</b><br>manual or auto"] --> GAP{"Gap since<br>closure?"}
GAP -->|"< 7 days"| SAME["New Incident<br><b>Same Campaign</b>"]
GAP -->|"> 7 days"| NEW["New Incident<br><b>New Campaign</b>"]
GAP -->|"No new activity"| DONE["Stays Closed"]
style CLOSED fill:#1b5e20,stroke:#66bb6a,color:#fff
style GAP fill:#00695c,stroke:#4db6ac,color:#fff
style SAME fill:#b71c1c,stroke:#ef5350,color:#fff
style NEW fill:#e65100,stroke:#ff9800,color:#fff
style DONE fill:#37474f,stroke:#78909c,color:#fff
New activity after closure always creates a new incident with a new ID — never reopens the old one. The old incident stays closed as part of the audit trail.
Incident Identity
Each incident is uniquely identified by WHO (actor) + WHERE (entity) — not by timestamps or attack types. One actor per entity = one open incident at a time.
| Field | What it determines |
|---|---|
| Incident ID | INC-{hash(actor_key + actor_type + entity_name + sequence)} — deterministic, stable |
| Sequence | Counts all previous CLOSED + FALSE_POSITIVE incidents for this actor + entity — increments on each new episode |
| Actor | The user, host, or IP being investigated |
| Entity | The customer site/tenant — ensures MSSP isolation |
| Attack Type | All active case types combined (e.g., APT_CHAIN,PASSWORD_SPRAYING) — updated each sync cycle |
| Campaign ID | Links related incidents across time within the same entity |
MSSP Entity Isolation
In MSSP environments, the same username (e.g., administrator) may exist across multiple customer entities. The system treats each as a completely separate actor:
flowchart LR
A1["<b>administrator</b><br>Site A"] --> INC1["INC-52e728f0<br>OPEN · Risk 85"]
A2["<b>administrator</b><br>Site B"] --> INC2["INC-2c72b927<br>OPEN · Risk 72"]
A3["<b>administrator</b><br>Site C"] --> INC3["No incident<br>Risk 45 · Triage only"]
style A1 fill:#0d47a1,stroke:#42a5f5,color:#fff
style A2 fill:#7b1fa2,stroke:#ce93d8,color:#fff
style A3 fill:#37474f,stroke:#78909c,color:#fff
style INC1 fill:#b71c1c,stroke:#ef5350,color:#fff
style INC2 fill:#e65100,stroke:#ff9800,color:#fff
style INC3 fill:#37474f,stroke:#78909c,color:#fff
Entity scoping applies to: incident creation, open-incident lookup, sequence counting, campaign linking, and auto-close. Closing an incident for administrator at Site A has zero effect on administrator at Site B.
Single-entity customers: Entity scoping is transparent — all data belongs to one entity, so it behaves as if scoping doesn't exist. No special configuration needed.
What the Incident Contains
The incident record is a lightweight tracking wrapper. Most data is queried live from source tables when the incident is viewed.
| Stored in Incident Record | Queried Live from Source Tables |
|---|---|
incident_id, campaign_id |
All alarms (alarm_actors) |
actor_key, actor_type, entity_name |
All sigma detections (sigma_alerts) |
attack_type (comma-separated) |
All threat cases (threat_cases) |
status (OPEN / IN_PROGRESS / CLOSED / FALSE_POSITIVE) |
Current risk score (actor_risk_summary) |
first_alarm_time, last_alarm_time |
MITRE tactics & techniques |
assigned_analyst, investigation_notes |
Raw logs and timeline |
| Resolution note (e.g., "Auto-closed...") | — |
flowchart LR
AA["<b>alarm_actors</b><br>SIEM alarms"] --> DETAIL["<b>Incident Detail Page</b><br>Shows ALL current data"]
SA["<b>sigma_alerts</b><br>RhythmX detections"] --> DETAIL
TC["<b>threat_cases</b><br>Correlated cases"] --> DETAIL
ARS2["<b>actor_risk_summary</b><br>7-factor score"] --> DETAIL
META["<b>Incident Record</b><br>ID · status · campaign"] --> DETAIL
style AA fill:#0d47a1,stroke:#42a5f5,color:#fff
style SA fill:#7b1fa2,stroke:#ce93d8,color:#fff
style TC fill:#b71c1c,stroke:#ef5350,color:#fff
style ARS2 fill:#4a148c,stroke:#9c27b0,color:#fff
style META fill:#37474f,stroke:#78909c,color:#fff
style DETAIL fill:#1b5e20,stroke:#66bb6a,color:#fff
Benefit: New alarms, detections, threat cases, and risk scores appear immediately — no need to refresh or rebuild the incident.
Campaign Linking
Campaigns group related incidents for the same actor to show attack progression over time.
Campaign Rule (applied when creating a new incident):
- Look at the most recent closed incident for this actor + entity
- If it was closed within the last 7 days (configurable:
INCIDENT_CAMPAIGN_LINK_DAYS) → reuse the samecampaign_id - If the gap is more than 7 days → create a new
campaign_id
All closure types (manual CLOSED, FALSE_POSITIVE, and auto-closed) are treated identically. Analyst manual closures do not break the campaign chain.
Campaign Example
Campaign CMP-123 — SERVER01 Compromise:
flowchart LR
INC1["<b>BRUTE_FORCE</b><br>Day 1–3 · Closed (auto)"] -->|"2 day gap"| INC2["<b>LATERAL_MOVEMENT</b><br>Day 5–8 · Closed (manual)"] -->|"1 day gap"| INC3["<b>RANSOMWARE</b><br>Day 9–now · Open"]
style INC1 fill:#1b5e20,stroke:#66bb6a,color:#fff
style INC2 fill:#1b5e20,stroke:#66bb6a,color:#fff
style INC3 fill:#b71c1c,stroke:#ef5350,color:#fff
| Day | Event | Incident | Status | Closure Type | Campaign |
|---|---|---|---|---|---|
| 1 | Brute force detected | INC-aaa created (OPEN) | OPEN | — | CMP-123 |
| 3 | No activity 24h | INC-aaa → CLOSED | CLOSED | Auto | CMP-123 |
| 5 | Lateral movement detected | INC-bbb created (OPEN) | OPEN | — | CMP-123 (linked) |
| 8 | Analyst closes | INC-bbb → CLOSED | CLOSED | Manual | CMP-123 |
| 10 | Ransomware attempt | INC-ccc created (OPEN) | OPEN | — | CMP-123 (linked) |
| 20 | New unrelated activity | INC-ddd created (OPEN) | OPEN | — | CMP-456 (new — gap > 7 days) |
Analysts see the full attack progression (brute force → lateral movement → ransomware) grouped under one campaign, even though it spans multiple incident records. The auto-closure on Day 3 and the manual closure on Day 8 are treated identically — neither breaks the campaign chain.
Campaign Timeline
gantt
title Campaign CMP-123 — SERVER01 Compromise
dateFormat YYYY-MM-DD
section Brute Force
INC-aaa (CLOSED auto) :done, bf, 2026-03-01, 3d
section Lateral Movement
INC-bbb (CLOSED manual) :done, lm, 2026-03-05, 4d
section Ransomware
INC-ccc (OPEN) :active, rw, 2026-03-09, 5d
Incident Detail View
When an analyst clicks an incident, the detail page shows:
Risk Intelligence Panel
- Risk Score with 7-factor breakdown (RhythmX / SIEM / Combined attribution)
- Attack Shape — Multi-Stage Compromise, Focused Persistent Attack, Broad Reconnaissance, etc.
- Confidence Level — HIGH / MEDIUM / LOW with reasoning
- Primary Driver — which factor contributed most
- Recommended Action — context-aware next step
Activity Data (Live)
- LogRhythm Alarms — grouped by rule, with raw log drill-down
- RhythmX Detections — grouped by rule, with ML outlier indicators
- Threat Cases — correlated attack patterns with severity and status
- MITRE ATT&CK Coverage — tactics and techniques as color-coded badges
- Timeline — first alert to last alert with duration
Timeframe Control
A dropdown on the detail page lets analysts scope the data:
- Incident Window (default) — only data between first and last alarm
- 1h / 4h / 12h / 1d / 3d / 7d / 14d / 30d / 90d — expand or narrow as needed
Analyst Actions
| Action | Description |
|---|---|
| Assign Analyst | Assign the incident to yourself or another team member |
| Change Status | Move through the lifecycle: OPEN → IN_PROGRESS → CLOSED / FALSE_POSITIVE |
| Add Investigation Notes | Document findings during the investigation |
| Add Resolution Notes | Document conclusions and remediation steps at close |
| Create External Ticket | Push the incident to Jira or ServiceNow with full risk context |
| Link External Ticket | Attach an existing external ticket reference (ID and URL) |
| Bulk Status Update | Select multiple incidents and change their status in a single action |
| View History | See the full audit trail — every status change, assignment, and note update |
| AI Triage | Run AI-powered analysis of the actor's behavior and risk factors |
External Ticket Integration
From the incident detail view, analysts can push incidents to Jira or ServiceNow. The ticket includes:
- Actor information and entity
- Risk score with full 7-factor breakdown
- MITRE ATT&CK tactics and techniques
- SLA status and target
- Alert rules triggered (up to 10, with overflow count)
- Investigation notes (if present)
Priority mapping:
| Risk Level | Jira Priority | ServiceNow Priority |
|---|---|---|
| Critical | Highest | 1 |
| High | High | 2 |
| Medium | Medium | 3 |
| Low | Low | 4 |
Auto-Push: When enabled, incidents meeting the severity threshold are automatically pushed to Jira/ServiceNow on creation. Failed pushes are retried up to 5 times via the retry queue.
SLA Tracking
SLA timer starts when the incident is created:
flowchart LR
C["<b>Critical ≥ 80</b><br>2 hours"] --> STATUS["On Track · At Risk · Breached · Resolved"]
H["<b>High 60–79</b><br>4 hours"] --> STATUS
M["<b>Medium 40–59</b><br>24 hours"] --> STATUS
L["<b>Low < 40</b><br>48 hours"] --> STATUS
style C fill:#b71c1c,stroke:#ef5350,color:#fff
style H fill:#e65100,stroke:#ff9800,color:#fff
style M fill:#f9a825,stroke:#ffee58,color:#000
style L fill:#1b5e20,stroke:#66bb6a,color:#fff
style STATUS fill:#37474f,stroke:#78909c,color:#fff
- On Track — Within the target window
- At Risk — 75%+ of the target time has elapsed
- Breached — Target time exceeded
- Resolved — Incident closed within the target
System State Model
Every incident has a system_state (machine-owned) and an analyst_status (human-owned). These are independent dimensions — the system manages threat progression while the analyst manages their workflow.
System States
| State | Condition | Ticket Action |
|---|---|---|
| MONITORING | 1 threat case AND risk < 40 | No ticket created |
| ACTIVE | risk ≥ 40 OR cases > 1 | No ticket created |
| ESCALATED | risk ≥ 70 OR (cases > 1 AND risk ≥ 40) | Ticket created after stability check |
| RESOLVED | No activity for 24h + no open cases | Ticket closed |
State Transitions with Cooldown
Escalation is fast (catch attacks quickly). De-escalation is slow (don't drop urgency prematurely).
| Transition | Cooldown | Direction |
|---|---|---|
| MONITORING → ACTIVE | 5 minutes | Escalation (fast) |
| ACTIVE → ESCALATED | 10 minutes | Escalation (fast) |
| ESCALATED → ACTIVE | 10 minutes | De-escalation (slow) |
| ACTIVE → MONITORING | 15 minutes | De-escalation (slow) |
| MONITORING → RESOLVED | 24 hours | Closure |
Incident Time Classification
Every incident is continuously classified by activity recency:
| Type | Condition | Behavior |
|---|---|---|
| ACTIVE | Last activity < 1 hour | Full escalation + ticket |
| RECENT | Last activity < 24h OR open threat cases with activity < 48h | Ticket with "monitor closely" warning |
| HISTORICAL | Last activity ≥ 24h, no recent threat cases | Ticket skipped — prevents noise |
Attack Trend
Each incident tracks risk trajectory:
| Trend | Condition | Meaning |
|---|---|---|
| ⬆ ACCELERATING | Risk increased by 5+ since last cycle | Threat is growing |
| ⬇ COOLING | Risk decreased by 5+ | Threat is subsiding |
| ➡ STABLE | Risk roughly unchanged | No significant change |
Ticket Sync (Jira / ServiceNow)
| Event | Ticket Action |
|---|---|
| ESCALATED + stable (2 cycles) | Create ticket (skip if HISTORICAL) |
| Risk level changes | Update ticket priority via API (not just comment) |
| State de-escalates | Add comment with reason |
| Re-escalation while analyst IN_PROGRESS | Add comment with RE-ESCALATION warning |
| RESOLVED | Close ticket (SNOW state=7 / Jira comment) |
Ticket Priority Mapping
| Risk Score | Base Priority | With HIGH/CRITICAL Confidence |
|---|---|---|
| ≥ 80 | P1 (Critical) | P1 (Critical) |
| 60 – 79 | P2 (High) | P1 (Critical) — confidence boost |
| 40 – 59 | P3 (Medium) | P3 (Medium) |
| < 40 | P4 (Low) | P4 (Low) |
Ownership Lock
When an analyst sets status to IN_PROGRESS, the system activates an ownership lock:
- State downgrade blocked — system will NOT move ESCALATED → ACTIVE
- Auto-close blocked — system will NOT move to RESOLVED
- Upgrades allowed — system CAN still escalate (adds RE-ESCALATION comment to ticket)
- Analyst must close manually when investigation is complete
Analyst Status (Independent)
| Status | Meaning | Who sets it |
|---|---|---|
| OPEN | New, unassigned | System (on creation) |
| IN_PROGRESS | Analyst is investigating | Analyst |
| CLOSED | Investigation complete | Analyst or system (auto-close if OPEN + RESOLVED) |
| FALSE_POSITIVE | Not a real threat | Analyst |
Scenario Walkthrough — Path A (Threat Case)
A user triggers a brute force detection. The system creates an incident, monitors it, and escalates as the attack progresses.
flowchart TD
T0["<b>Minute 0</b><br>Threat case fires: Brute Force<br>Risk: 39 · 1 case · 10 sigma alerts"] --> INC["<b>Incident Created</b><br>Path A — threat case exists<br>State: MONITORING<br>Type: ACTIVE<br>Trend: ➡ STABLE"]
INC --> T2["<b>Minute 2</b><br>More sigma alerts + LR alarms arrive<br>Risk climbs to 55"]
T2 --> ST1["State: MONITORING → <b>ACTIVE</b><br><i>(5 min cooldown starts)</i>"]
ST1 --> T7["<b>Minute 7</b><br>Cooldown passed<br>2nd threat case: Lateral Movement<br>Risk: 65"]
T7 --> ST2["State: <b>ACTIVE</b><br>Trend: ⬆ ACCELERATING<br><i>No ticket yet</i>"]
ST2 --> T12["<b>Minute 12</b><br>3rd threat case: Persistence<br>Risk: 76 · 3 cases · 50 sigma + 200 LR alarms"]
T12 --> ST3["State: ACTIVE → <b>ESCALATED</b><br><i>(10 min cooldown starts)</i>"]
ST3 --> T22["<b>Minute 22</b><br>Cooldown passed · Stability check:<br>Cycle 1/2 — wait"]
T22 --> T24["<b>Minute 24</b><br>Stability check:<br>Cycle 2/2 — <b>STABLE</b>"]
T24 --> TICKET["<b>Ticket Created</b><br>SNOW/Jira<br>Priority: P1 (risk 76 + HIGH confidence)<br>Primary Driver: 3 threat cases<br>Attack Trend: ⬆ ACCELERATING<br>Activity Status: ACTIVE"]
TICKET --> SYNC["<b>Ongoing Sync</b><br>Every 5 min:<br>· Risk changes → update priority<br>· New cases → add comment<br>· Analyst sets IN_PROGRESS → ownership lock"]
SYNC --> T24H["<b>24 hours later</b><br>No new activity · All cases closed<br>Risk dropped to 25"]
T24H --> RES["State: <b>RESOLVED</b><br>SNOW ticket closed<br>analyst_status: CLOSED (auto)"]
style T0 fill:#37474f,stroke:#78909c,color:#fff
style INC fill:#546e7a,stroke:#90a4ae,color:#fff
style T2 fill:#e65100,stroke:#ff9800,color:#fff
style ST1 fill:#f9a825,stroke:#ffee58,color:#000
style T7 fill:#ef6c00,stroke:#ffb74d,color:#fff
style ST2 fill:#f57f17,stroke:#fff176,color:#000
style T12 fill:#d84315,stroke:#ff7043,color:#fff
style ST3 fill:#c62828,stroke:#ef9a9a,color:#fff
style T22 fill:#b71c1c,stroke:#ef5350,color:#fff
style T24 fill:#b71c1c,stroke:#ef5350,color:#fff
style TICKET fill:#0d47a1,stroke:#42a5f5,color:#fff
style SYNC fill:#1a237e,stroke:#534bae,color:#fff
style T24H fill:#2e7d32,stroke:#81c784,color:#fff
style RES fill:#1b5e20,stroke:#66bb6a,color:#fff
Risk Score Progression (Path A)
| Time | Threat Cases | Sigma Alerts | LR Alarms | Risk Score | State |
|---|---|---|---|---|---|
| Min 0 | 1 (Brute Force) | 10 | 0 | 39 | MONITORING |
| Min 2 | 1 | 25 | 50 | 55 | ACTIVE |
| Min 7 | 2 (+Lateral Movement) | 35 | 120 | 65 | ACTIVE |
| Min 12 | 3 (+Persistence) | 50 | 200 | 76 | ESCALATED |
| Min 24 | 3 | 50 | 200 | 76 | ESCALATED → Ticket |
| +24h | 0 (all closed) | 50 | 200 | 25 | RESOLVED |
Scenario Walkthrough — Path B (Risk Score Only)
A host generates high volume of diverse detections but no threat cases. Risk crosses 70 from sigma + SIEM signals alone.
flowchart TD
T0["<b>Hour 0</b><br>Host: srv-web-01<br>50 sigma alerts · 500 LR alarms<br>8 unique rules · 4 MITRE tactics<br>Risk: 72 · 0 threat cases"] --> INC["<b>Incident Created</b><br>Path B — risk ≥ 70<br>State: ESCALATED<br>Type: ACTIVE<br>Trend: ➡ STABLE"]
INC --> STAB["<b>+10 min</b><br>Stability check: 2/2 — STABLE"]
STAB --> TICKET["<b>Ticket Created</b><br>SNOW/Jira<br>Priority: P2 (risk 72, MEDIUM confidence)<br>Primary Driver: Risk Score 72/100<br>Activity Status: ACTIVE"]
TICKET --> T4H["<b>+4 hours</b><br>More alerts arrive · Risk: 85<br>Confidence: HIGH"]
T4H --> PRI["<b>Priority Updated</b><br>P2 → P1 (risk 85 + HIGH confidence)<br>SNOW API PATCH"]
PRI --> T12H["<b>+12 hours</b><br>Activity slows · Risk: 58"]
T12H --> DEESC["State: ESCALATED → <b>ACTIVE</b><br><i>(15 min cooldown passed)</i><br>Comment added to ticket"]
DEESC --> T48H["<b>+48 hours</b><br>No new activity · Risk: 30"]
T48H --> RES["State: <b>RESOLVED</b><br>SNOW ticket closed"]
style T0 fill:#e65100,stroke:#ff9800,color:#fff
style INC fill:#c62828,stroke:#ef9a9a,color:#fff
style STAB fill:#b71c1c,stroke:#ef5350,color:#fff
style TICKET fill:#0d47a1,stroke:#42a5f5,color:#fff
style T4H fill:#d84315,stroke:#ff7043,color:#fff
style PRI fill:#4a148c,stroke:#9c27b0,color:#fff
style T12H fill:#f9a825,stroke:#ffee58,color:#000
style DEESC fill:#f57f17,stroke:#fff176,color:#000
style T48H fill:#2e7d32,stroke:#81c784,color:#fff
style RES fill:#1b5e20,stroke:#66bb6a,color:#fff
Risk Score Progression (Path B)
| Time | Threat Cases | Sigma Alerts | LR Alarms | Risk Score | State | Ticket |
|---|---|---|---|---|---|---|
| Hour 0 | 0 | 50 | 500 | 72 | ESCALATED | — |
| +10 min | 0 | 50 | 500 | 72 | ESCALATED | Created (P2) |
| +4 hours | 0 | 80 | 800 | 85 | ESCALATED | Priority → P1 |
| +12 hours | 0 | 80 | 800 | 58 | ACTIVE | Comment added |
| +48 hours | 0 | 80 | 800 | 30 | RESOLVED | Closed |
Scenario — HISTORICAL Skip (No False Ticket)
An actor had high risk 3 days ago but is no longer active. The system creates an incident but does NOT generate a ticket.
flowchart TD
T0["<b>3 days ago</b><br>Risk was 74 · 2 threat cases<br>Activity stopped"] --> TODAY["<b>Today</b><br>Risk still 72 (from cached data)<br>No new activity · Cases still open"]
TODAY --> INC["<b>Incident exists</b><br>State: ESCALATED<br>Type: <b>HISTORICAL</b><br><i>(last activity > 24h, cases open but stale > 48h)</i>"]
INC --> STAB["Stability check passes"]
STAB --> SKIP["<b>TICKET SKIPPED</b><br>Log: 'Skipping auto-ticket — HISTORICAL'<br><i>No noise for analyst</i>"]
SKIP --> LATER["<b>Later — new activity appears</b><br>Fresh sigma alerts · Risk: 78"]
LATER --> RECLASS["Type: HISTORICAL → <b>ACTIVE</b><br>Trend: ⬆ ACCELERATING"]
RECLASS --> TICKET["<b>NOW ticket is created</b><br>Because incident is ACTIVE again"]
style T0 fill:#37474f,stroke:#78909c,color:#fff
style TODAY fill:#546e7a,stroke:#90a4ae,color:#fff
style INC fill:#78909c,stroke:#b0bec5,color:#fff
style STAB fill:#78909c,stroke:#b0bec5,color:#fff
style SKIP fill:#1b5e20,stroke:#66bb6a,color:#fff
style LATER fill:#e65100,stroke:#ff9800,color:#fff
style RECLASS fill:#d84315,stroke:#ff7043,color:#fff
style TICKET fill:#0d47a1,stroke:#42a5f5,color:#fff
Scenario — Ownership Lock (Analyst Protection)
An analyst is actively investigating. The system protects their workflow.
flowchart TD
ESC["<b>Incident ESCALATED</b><br>Risk: 78 · Ticket: SNOW-1234"] --> ANALYST["<b>Analyst sets IN_PROGRESS</b><br>Ownership lock activates"]
ANALYST --> DROP["<b>Risk drops to 55</b><br>System wants: ESCALATED → ACTIVE"]
DROP --> BLOCK["<b>BLOCKED</b><br>Ownership lock prevents downgrade<br>State stays: ESCALATED<br><i>Analyst is working, don't interfere</i>"]
ANALYST --> SPIKE["<b>Risk spikes to 92</b><br>New threat case appears"]
SPIKE --> REESC["<b>RE-ESCALATION</b><br>Comment added to SNOW-1234:<br>'⚠️ Risk increased to 92 while<br>analyst is investigating'<br>Priority: P2 → P1"]
ANALYST --> CLOSE["<b>Analyst closes investigation</b><br>analyst_status: CLOSED<br>Ownership lock released"]
style ESC fill:#b71c1c,stroke:#ef5350,color:#fff
style ANALYST fill:#0d47a1,stroke:#42a5f5,color:#fff
style DROP fill:#f9a825,stroke:#ffee58,color:#000
style BLOCK fill:#1b5e20,stroke:#66bb6a,color:#fff
style SPIKE fill:#d84315,stroke:#ff7043,color:#fff
style REESC fill:#c62828,stroke:#ef9a9a,color:#fff
style CLOSE fill:#2e7d32,stroke:#81c784,color:#fff
Configuration
All settings are configurable in .env.production:
| Setting | Default | Description |
|---|---|---|
INCIDENT_SYNC_ENABLED |
true |
Enable/disable incident sync service |
INCIDENT_MIN_RISK_SCORE |
70 |
Minimum risk score for Path B qualification |
INCIDENT_RISK_FRESHNESS_HOURS |
24 |
Legacy — no longer used (recency is in the risk score) |
INCIDENT_THREAT_CASE_DAYS |
30 |
Threat case lookback window (days) |
INCIDENT_AUTO_CLOSE_HOURS |
24 |
Auto-close after this many hours of inactivity |
INCIDENT_CAMPAIGN_LINK_DAYS |
7 |
Link incidents within this window to same campaign |
AUTO_PUSH_MIN_SEVERITY |
CRITICAL |
Minimum severity for auto-push to Jira/ServiceNow |
RETRY_MAX_ATTEMPTS |
5 |
Max retry attempts for failed ticket pushes |
FEED_RATE_LIMIT |
120/minute |
External API rate limit per API key |