Query Details

RULE 16 Sentinel Analytics Rule Deleted

Query

// Rule    : Azure Sentinel - Analytics Rule Deleted or Disabled
// Severity: High
// Tactics : DefenseEvasion
// MITRE   : T1562
// Freq    : PT1H   Period: PT2H
//==========================================================================================

let KnownIaCPatterns = dynamic(["terraform", "bicep", "pipeline", "github", "pulumi", "devops"]);
// Alert rule DELETE = removal; WRITE can cover status change to disabled — both are suspicious
let SentinelRuleOps = dynamic([
    "MICROSOFT.SECURITYINSIGHTS/ALERTRULES/DELETE",
    "MICROSOFT.SECURITYINSIGHTS/ALERTRULES/WRITE"
]);
AzureActivity
| where TimeGenerated > ago(2h)
| where OperationNameValue has_any (SentinelRuleOps)
| where ActivityStatusValue =~ "Success"
| where not(tolower(Caller) has_any (KnownIaCPatterns))
| where isnotempty(CallerIpAddress)
| where CallerIpAddress !startswith "168.63." and CallerIpAddress !startswith "169.254."
// Separate deletions from modifications to differentiate severity in the alert
| extend OperationType = iff(OperationNameValue has "DELETE", "Delete", "Modify/Disable")
| summarize
    OperationCount     = count(),
    DeleteCount        = countif(OperationType == "Delete"),
    ModifyCount        = countif(OperationType == "Modify/Disable"),
    AffectedRules      = make_set(ResourceId, 20),
    Operations         = make_set(OperationNameValue, 5),
    AffectedWorkspaces = make_set(ResourceGroup, 5),
    SourceIPs          = make_set(CallerIpAddress, 5),
    CallerIP           = any(CallerIpAddress),
    FirstSeen          = min(TimeGenerated),
    LastSeen           = max(TimeGenerated)
    by Caller, SubscriptionId
// Tuned: modification threshold 3 -> 5 (bulk rule tuning sessions commonly touch 3-4 rules
// during onboarding). Deletion trigger is unchanged — any single rule DELETE is still
// investigated because rule removal is high-signal.
| where DeleteCount >= 1 or ModifyCount >= 5    // any delete or 5+ modifications
| extend
    AccountName      = tostring(split(Caller, "@")[0]),
    AccountUPNSuffix = tostring(split(Caller, "@")[1])

Explanation

This query is designed to monitor and alert on suspicious activities related to the deletion or disabling of Azure Sentinel analytics rules. Here's a simplified breakdown of what the query does:

  1. Purpose: The query aims to detect potentially unauthorized or suspicious deletions or modifications of Azure Sentinel analytics rules, which could indicate attempts at defense evasion.

  2. Scope: It looks at Azure activity logs from the past 2 hours.

  3. Operations Monitored: It focuses on two types of operations:

    • Deletion of alert rules.
    • Modifications that could include disabling alert rules.
  4. Exclusions:

    • It excludes operations initiated by known infrastructure-as-code (IaC) patterns like "terraform", "bicep", "pipeline", etc.
    • It filters out internal Azure IP addresses that start with "168.63." or "169.254.".
  5. Classification:

    • It categorizes operations into "Delete" or "Modify/Disable" based on the type of operation performed.
  6. Aggregation:

    • It summarizes the data by counting the number of delete and modify operations, listing affected rules, workspaces, and source IPs, and noting the first and last time the operations were seen.
  7. Alert Conditions:

    • An alert is triggered if there is at least one deletion or if there are five or more modifications. This threshold is set to distinguish between routine bulk modifications and potentially malicious activity.
  8. Output:

    • It provides details about the caller (user) who performed the operations, including their account name and domain.

In essence, this query helps security teams identify and investigate potentially malicious changes to security rules in Azure Sentinel, ensuring that any unauthorized attempts to disable or delete these rules are promptly addressed.

Details

David Alonso profile picture

David Alonso

Released: July 27, 2026

Tables

AzureActivity

Keywords

AzureSentinelAnalyticsRuleDefenseEvasionMITREActivityOperationNameValueStatusCallerIPAddressResourceIDGroupSubscriptionAccountUPNSuffix

Operators

letdynamicagohas_any=~tolowerisnotempty!startswithextendiffsummarizecountcountifmake_setanyminmaxbysplittostring

MITRE Techniques

Actions

GitHub