← Back to SOC feed Coverage →

Conditional Access policy exclusion added

kql MEDIUM Azure-Sentinel
T1556.009
AuditLogs
backdoorevasionhuntingmicrosoftofficial
This rule was pulled from an open-source repository and enriched with AI. Validate in a test environment before deploying to production.
View original rule at Azure-Sentinel →
Retrieved: 2026-07-31T11:00:00Z · Confidence: medium

Hunt Hypothesis

This hunt detects adversaries who subtly weaken security posture by adding user or location exclusions to Conditional Access policies, allowing them to bypass MFA and device compliance requirements without triggering standard state-change alerts. A proactive search is essential in Azure Sentinel because these stealthy modifications often go unnoticed until an attacker leverages the exclusion to gain unauthorized access or pivot within the environment.

KQL Query

let timeframe = 14d;
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where Category =~ "Policy"
| where OperationName =~ "Update conditional access policy"
| where Result =~ "success"
| mv-expand ModProp = TargetResources[0].modifiedProperties
| extend PropName = tostring(ModProp.displayName)
| extend OldValue = tostring(ModProp.oldValue)
| extend NewValue = tostring(ModProp.newValue)
| where PropName !~ "State"
| where PropName has "Condition" or NewValue has "exclude" or OldValue has "exclude"
| extend PolicyName = tostring(TargetResources[0].displayName)
| extend PolicyId   = tostring(TargetResources[0].id)
| extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
| extend ActorApp = tostring(InitiatedBy.app.displayName)
| extend Actor    = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| extend ActorIp  = iff(
      isnotempty(tostring(InitiatedBy.user.ipAddress)),
      tostring(InitiatedBy.user.ipAddress),
      tostring(InitiatedBy.app.ipAddress))
| extend AccountName      = iff(ActorUpn has "@", tostring(split(ActorUpn, "@")[0]), Actor)
| extend AccountUPNSuffix = iff(ActorUpn has "@", tostring(split(ActorUpn, "@")[1]), "")
| project
    TimeGenerated,
    PolicyName,
    PolicyId,
    PropName,
    OldValue,
    NewValue,
    Actor,
    AccountName,
    AccountUPNSuffix,
    ActorIp,
    CorrelationId
| sort by TimeGenerated desc

Analytic Rule Definition

id: a14106c1-af19-41fb-9fbd-6d9ef402537b
name: Conditional Access policy exclusion added
description: |
  Identifies Conditional Access policy updates that narrow scope via exclusions rather than change the enabled state, a technique attackers use to bypass enforcement without triggering state-change monitoring.
description-detailed: |
  An attacker with Conditional Access Administrator or Global Administrator
  access can narrow a policy's scope by adding their own account, a compromised
  guest account, or a service principal to its exclusion list. This achieves the
  same practical bypass as disabling the policy, without the state change that
  most defenses monitor for, and without interrupting enforcement for every other
  user in the tenant.
  This query intentionally excludes plain enabled/disabled state transitions,
  which are covered separately, and instead surfaces condition-level edits so
  analysts can review the raw old and new values for scope-narrowing changes
  such as a growing exclude-users or exclude-groups list.
  Analysts must validate every result. Benign matches include legitimate policy
  tuning, break-glass account exclusions documented in change records, and
  scheduled policy reviews. The signal is highest when the excluded identity is
  privileged, recently created, or not a known break-glass account.
  MITRE ATT&CK documents this exact pattern under T1556.009: threat actors,
  including Scattered Spider, have added trusted locations and exclusions to
  Conditional Access policies in real intrusions to maintain access after
  initial compromise.
  References:
  - https://learn.microsoft.com/entra/identity/conditional-access/overview
  - https://learn.microsoft.com/entra/identity/monitoring-health/reference-audit-activities
  - https://attack.mitre.org/techniques/T1556/009/
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1556.009
query: |
  let timeframe = 14d;
  AuditLogs
  | where TimeGenerated >= ago(timeframe)
  | where Category =~ "Policy"
  | where OperationName =~ "Update conditional access policy"
  | where Result =~ "success"
  | mv-expand ModProp = TargetResources[0].modifiedProperties
  | extend PropName = tostring(ModProp.displayName)
  | extend OldValue = tostring(ModProp.oldValue)
  | extend NewValue = tostring(ModProp.newValue)
  | where PropName !~ "State"
  | where PropName has "Condition" or NewValue has "exclude" or OldValue has "exclude"
  | extend PolicyName = tostring(TargetResources[0].displayName)
  | extend PolicyId   = tostring(TargetResources[0].id)
  | extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
  | extend ActorApp = tostring(InitiatedBy.app.displayName)
  | extend Actor    = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
  | extend ActorIp  = iff(
        isnotempty(tostring(InitiatedBy.user.ipAddress)),
        tostring(InitiatedBy.user.ipAddress),
        tostring(Initiate

Required Data Sources

Sentinel TableNotes
AuditLogsEnsure this data connector is enabled

MITRE ATT&CK Context

References

False Positive Guidance

Here are 4 specific false positive scenarios for the Conditional Access policy exclusion added detection rule, including suggested filters and exclusions:

Original source: https://github.com/Azure/Azure-Sentinel/blob/main/Hunting Queries/AuditLogs/ConditionalAccessPolicyExclusionAdded.yaml