Query Details

Alert Efficiency

Query

# Alert Efficiency

## Query Information

#### Description
The rule below can be used to calculate the efficiency of custom detection rules in your environment. The line ```| where AlertName startswith "[DxBP]"``` should be replaced with the prefix of your custom detection rules or should be removed completely to include build in rules as well.

## Sentinel
```KQL
let TimeRange = 365d;
SecurityIncident
| where TimeGenerated > ago(TimeRange)
// Collect last argumtent of incident
| summarize arg_max(TimeGenerated, Title, AlertIds, Severity, Classification) by IncidentNumber
// Only filter on closed incidents.
| where isnotempty(Classification)
| mv-expand AlertIds to typeof(string)
| join kind=inner ( SecurityAlert 
    // Filter Custom Detection Prefix Tenant
    | where AlertName startswith "[DxBP]"
    | where TimeGenerated > ago(TimeRange) 
    | summarize arg_max(TimeGenerated, SystemAlertId, AlertName) by SystemAlertId) 
    on $left.AlertIds == $right.SystemAlertId
// Calculate statistics
| summarize
    // Total unique alerts raised for this detection (distinct SystemAlertId).
    // Use this as the main denominator when each alert has a single classification.
    TotalAlertsTriggered = dcount(SystemAlertId),
    // Number of alerts whose outcome wasn’t concluded.
    // High values indicate investigation load and potential workflow gaps.
    TotalUndetermined    = countif(Classification == "Undetermined"),
    // Number of alerts correctly identified as benign (expected/allowed behavior).
    // Useful to quantify “known good but noisy” detections that still trigger.
    TotalBenignPositive  = countif(Classification == "BenignPositive"),
    // Number of alerts confirmed as genuinely malicious.
    // This is the primary “value delivered” signal for the detection.
    TotalTruePositive    = countif(Classification == "TruePositive"),
    // Number of alerts that were investigated and proven not malicious.
    // This directly reflects analyst toil and detection noise.
    TotalFalsePositive   = countif(Classification == "FalsePositive")
  by AlertName
| extend
    // Share of all triggered alerts that were true positives.
    // Higher is better; indicates yield of useful alerts.
    PctTruePositive      = round(100.0 * todouble(TotalTruePositive)
                                 / iif(TotalAlertsTriggered==0, real(null), todouble(TotalAlertsTriggered)), 2),
    // Share of all triggered alerts that were false positives.
    // Lower is better; indicates noise and wasted investigation effort.
    PctFalsePositive     = round(100.0 * todouble(TotalFalsePositive)
                                 / iif(TotalAlertsTriggered==0, real(null), todouble(TotalAlertsTriggered)), 2),
    // Share of all triggered alerts that were benign positives.
    // Helps separate “expected but noisy” from truly incorrect detections.
    PctBenignPositive    = round(100.0 * todouble(TotalBenignPositive)
                                 / iif(TotalAlertsTriggered==0, real(null), todouble(TotalAlertsTriggered)), 2),
    // Share of all triggered alerts that remain undetermined.
    // Indicates backlog or ambiguity in triage/investigation process.
    PctUndetermined      = round(100.0 * todouble(TotalUndetermined)
                                 / iif(TotalAlertsTriggered==0, real(null), todouble(TotalAlertsTriggered)), 2),
    // Precision (a.k.a. Positive Predictive Value): of all alerts judged suspicious (TP+FP),
    // what fraction were truly malicious? Higher is better (less analyst toil).
    PrecisionPct         = round(100.0 * todouble(TotalTruePositive)
                                 / iif(TotalTruePositive + TotalFalsePositive == 0,
                                       real(null),
                                       todouble(TotalTruePositive + TotalFalsePositive)), 2),
    // False Discovery Rate: complement of precision over the same TP+FP set.
    // Lower is better; directly represents the share of erroneous detections.
    FalseDiscoveryRatePct= round(100.0 * todouble(TotalFalsePositive)
                                 / iif(TotalTruePositive + TotalFalsePositive == 0,
                                       real(null),
                                       todouble(TotalTruePositive + TotalFalsePositive)), 2)
// Sort to surface the most effective detections first: high precision, then high TP share.
| sort by PrecisionPct desc, PctTruePositive desc
```

Explanation

This query is designed to evaluate the efficiency of custom detection rules in a security environment, specifically within Microsoft Sentinel. Here's a simplified breakdown of what the query does:

  1. Time Range: It looks at security incidents from the past 365 days.

  2. Incident Filtering: It focuses on incidents that have been closed and have a classification (meaning they have been reviewed and categorized).

  3. Alert Matching: It matches these incidents with security alerts that have a specific prefix ("[DxBP]") in their names, which is meant to identify custom detection rules. You can modify or remove this filter to include built-in rules.

  4. Statistics Calculation: For each alert type, it calculates:

    • Total number of alerts triggered.
    • Number of alerts with an "Undetermined" classification.
    • Number of alerts classified as "Benign Positive" (false alarms that are expected behavior).
    • Number of alerts classified as "True Positive" (correctly identified threats).
    • Number of alerts classified as "False Positive" (incorrectly identified as threats).
  5. Efficiency Metrics: It computes several percentages to assess the efficiency of the alerts:

    • PctTruePositive: The percentage of alerts that were true positives.
    • PctFalsePositive: The percentage of alerts that were false positives.
    • PctBenignPositive: The percentage of alerts that were benign positives.
    • PctUndetermined: The percentage of alerts that remain undetermined.
    • PrecisionPct: The precision of the alerts, indicating the proportion of true positives among all positive alerts (true positives + false positives).
    • FalseDiscoveryRatePct: The rate of false discoveries, representing the proportion of false positives among all positive alerts.
  6. Sorting: Finally, it sorts the results to highlight the most effective detection rules, prioritizing those with higher precision and a higher percentage of true positives.

Overall, this query helps security analysts understand which detection rules are most effective and where there might be room for improvement in reducing false positives and undetermined alerts.

Details

Bert-Jan Pals profile picture

Bert-Jan Pals

Released: February 22, 2026

Tables

SecurityIncidentSecurityAlert

Keywords

SecurityIncidentSecurityAlertAlertNameAlertIdsSeverityClassificationSystemAlertIdTimeGeneratedTitleIncidentNumber

Operators

letwheresummarizearg_maxbyisnotemptymv-expandtotypeofjoinkindstartswithcountifextendroundtodoubleiifrealnullsortdesc

Actions