The Incident Contained Three Alerts — The Fourth Was Somewhere Else
The Microsoft Sentinel incident looked complete.
Three alerts.
One user.
One device.
A tidy sequence of suspicious activity.
The incident timeline seemed to explain what had happened.
But Agent Foskett noticed that one entity appeared earlier in the raw evidence than it did inside the incident.
So where was the alert that explained it?
It existed.
It simply was not part of this incident.

The Incident Was Not the Whole Investigation.
Incidents group alerts to help analysts investigate. The surrounding telemetry can still contain related evidence outside that grouping.
Three alerts can still be an incomplete story
That grouping is enormously useful.
But Agent Foskett treated it as a starting scope — not an unquestionable boundary.
An incident tells you which alerts were grouped together. It does not guarantee that every related security event has been grouped into the same incident.
Start with the incident record
SecurityIncident table includes incident metadata and the alert identifiers associated with the incident. Agent Foskett first established exactly which alerts Sentinel had placed inside the case.- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let TargetIncident = "INCIDENT-NUMBER-HERE";
SecurityIncident
| where TimeGenerated > ago(30d)
| where IncidentNumber == toint(TargetIncident)
| summarize arg_max(TimeGenerated, *) by IncidentNumber
| project IncidentNumber,
Title,
Severity,
Status,
CreatedTime,
FirstActivityTime,
LastActivityTime,
AlertIdsThe incident boundary was now explicit
That gave Agent Foskett something concrete to compare against the wider alert population.
He was no longer asking vaguely whether something might be missing.
He knew exactly which alerts were inside the incident — and could now search for related alerts outside it.
Expand the alerts inside the incident
AlertIds and joined them to SecurityAlert.SystemAlertId. This reconstructed the three alerts Sentinel had correlated into the case.- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
let TargetIncident = 12345;
let IncidentAlerts =
SecurityIncident
| where TimeGenerated > ago(30d)
| where IncidentNumber == TargetIncident
| summarize arg_max(TimeGenerated, *) by IncidentNumber
| mv-expand AlertId = AlertIds
| project IncidentNumber,
AlertId = tostring(AlertId);
IncidentAlerts
| join kind=inner (
SecurityAlert
| where TimeGenerated > ago(30d)
| project SystemAlertId,
TimeGenerated,
AlertName,
AlertSeverity,
ProviderName,
CompromisedEntity,
Entities
) on $left.AlertId == $right.SystemAlertId
| project TimeGenerated,
IncidentNumber,
SystemAlertId,
AlertName,
AlertSeverity,
ProviderName,
CompromisedEntity,
Entities
| order by TimeGenerated ascOne entity appeared before the incident's first alert
But when Agent Foskett pivoted into the surrounding telemetry, the device appeared in suspicious activity before the first alert in the incident.
That meant either the activity had not generated an alert — or another alert existed elsewhere.
The incident timeline began too late to explain the first suspicious evidence.
Search all alerts for the shared entity
SecurityAlert. In a real case, the strongest pivot might be a device, account, IP address, URL, process or another entity extracted from the incident. This example uses the compromised-entity field as a first pass.- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
let TargetEntity = "LAPTOP-042";
SecurityAlert
| where TimeGenerated > ago(14d)
| where CompromisedEntity =~ TargetEntity
or Entities has TargetEntity
| project TimeGenerated,
SystemAlertId,
AlertName,
AlertSeverity,
ProviderName,
CompromisedEntity,
Entities
| order by TimeGenerated ascThere it was
Its timestamp preceded the three alerts inside the incident.
It involved the same device and helped explain how the later activity began.
But its
SystemAlertId was not one of the IDs associated with the target incident.The alert existed. The correlation boundary had placed it somewhere else.
Prove which related alerts are outside the incident
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
let TargetIncident = 12345;
let TargetEntity = "LAPTOP-042";
let IncidentAlertIds =
SecurityIncident
| where TimeGenerated > ago(30d)
| where IncidentNumber == TargetIncident
| summarize arg_max(TimeGenerated, *) by IncidentNumber
| mv-expand AlertId = AlertIds
| summarize make_set(tostring(AlertId));
SecurityAlert
| where TimeGenerated > ago(14d)
| where CompromisedEntity =~ TargetEntity
or Entities has TargetEntity
| extend InTargetIncident =
SystemAlertId in (IncidentAlertIds)
| project TimeGenerated,
SystemAlertId,
AlertName,
AlertSeverity,
ProviderName,
InTargetIncident
| order by TimeGenerated ascWhy might the fourth alert be elsewhere?
Different analytics rules can have different incident-creation and grouping behaviour.
Alerts can be generated at different times.
Incident grouping can depend on configured matching logic and time windows.
Some Microsoft security alerts may also arrive through different providers or product integrations.
A missing alert from one incident is not automatically evidence of a Sentinel failure.
The job was to establish the relationship and then inspect the applicable incident and analytics configuration.
Search for the alert's own incident context
This mattered because two incident records could represent different slices of the same underlying attack.
Case boundaries can divide evidence that an attacker never divided.
Find incidents containing the fourth alert
SecurityIncident.AlertIds to determine whether Sentinel associated it with another incident.- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
let FourthAlertId =
"00000000-0000-0000-0000-000000000000";
SecurityIncident
| where TimeGenerated > ago(30d)
| where AlertIds has FourthAlertId
| summarize arg_max(TimeGenerated, *) by IncidentNumber
| project IncidentNumber,
Title,
Severity,
Status,
Owner,
CreatedTime,
FirstActivityTime,
LastActivityTime,
AlertIds
| order by CreatedTime ascThen return to the underlying telemetry
He pivoted from the shared entities and timestamps into the raw identity, endpoint, network or cloud telemetry behind the detections.
Alerts tell you what detection logic noticed. Source events tell you what the environment recorded.
Build the expanded attack timeline
What Agent Foskett checked
What the evidence can and cannot prove
SecurityIncident.AlertIds identifies alerts associated with an incident record, while SecurityAlert.SystemAlertId identifies individual alerts available in the workspace.A related alert appearing outside the target incident proves only that it was not included in that incident's alert-ID set at the time represented by the record being examined.
It does not by itself prove that incident grouping malfunctioned.
The analyst must investigate grouping configuration, timestamps, entities, alert providers and the underlying telemetry before explaining why the alert was elsewhere.
The lesson
All three mattered.
But the fourth alert changed the beginning of the timeline.
If Agent Foskett had investigated only what was already grouped into the incident, he would have started the story too late.
An incident is a correlation of evidence. It is not necessarily the boundary of the attack.
Related investigations
Final thought
They give analysts a case to open, assign, classify and investigate.
But attackers do not organise their activity around incident numbers.
Agent Foskett used the incident as the doorway — not the walls of the investigation.
The Logs Already Knew! 🔎

