← Back to SOC feed Coverage →

Conditional Access Policy Modified by New User

kql MEDIUM Azure-Sentinel
T1078.004
AuditLogs
backdoormicrosoftofficial
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-03-25T03:06:09Z · Confidence: medium

Hunt Hypothesis

A user with no recent history of modifying Conditional Access Policies is attempting to alter security controls, potentially weakening organizational defenses. SOC teams should proactively hunt for this behavior to identify and mitigate unauthorized changes to critical security configurations in Azure Sentinel.

KQL Query

let known_users = (AuditLogs
  | where TimeGenerated between(ago(14d)..ago(1d))
  | where OperationName has "conditional access policy"
  | where Result =~ "success"
  | extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
  | summarize by InitiatingUserPrincipalName);
  AuditLogs
  | where TimeGenerated > ago(1d)
  | where OperationName has "conditional access policy"
  | where Result =~ "success"
  | extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
  | extend InitiatingAppId = tostring(InitiatedBy.app.appId)
  | extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
  | extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
  | extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
  | extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
  | extend CAPolicyName = tostring(TargetResources[0].displayName)
  | where InitiatingUserPrincipalName !in (known_users)
  | extend NewPolicyValues = TargetResources[0].modifiedProperties[0].newValue
  | extend OldPolicyValues = TargetResources[0].modifiedProperties[0].oldValue
  | extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
  | project-reorder TimeGenerated, OperationName, CAPolicyName, InitiatingAppId, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, NewPolicyValues, OldPolicyValues

Analytic Rule Definition

id: 25a7f951-54b7-4cf5-9862-ebc04306c590
name: Conditional Access Policy Modified by New User
description: |
  'Detects a Conditional Access Policy being modified by a user who has not modified a policy in the last 14 days.
    A threat actor may try to modify policies to weaken the security controls in place.
    Investigate any change to ensure they are approved.
    Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-infrastructure#conditional-access'
severity: Medium
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
queryFrequency: 1d
queryPeriod: 14d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1078.004
tags:
  - AADSecOpsGuide
query: |
  let known_users = (AuditLogs
    | where TimeGenerated between(ago(14d)..ago(1d))
    | where OperationName has "conditional access policy"
    | where Result =~ "success"
    | extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
    | summarize by InitiatingUserPrincipalName);
    AuditLogs
    | where TimeGenerated > ago(1d)
    | where OperationName has "conditional access policy"
    | where Result =~ "success"
    | extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
    | extend InitiatingAppId = tostring(InitiatedBy.app.appId)
    | extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
    | extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
    | extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
    | extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
    | extend CAPolicyName = tostring(TargetResources[0].displayName)
    | where InitiatingUserPrincipalName !in (known_users)
    | extend NewPolicyValues = TargetResources[0].modifiedProperties[0].newValue
    | extend OldPolicyValues = TargetResources[0].modifiedProperties[0].oldValue
    | extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
    | project-reorder TimeGenerated, OperationName, CAPolicyName, InitiatingAppId, InitiatingAppName, InitiatingAppServicePrincipalId, InitiatingUserPrincipalName, InitiatingAadUserId, InitiatingIPAddress, NewPolicyValues, OldPolicyValues
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: InitiatingUserPrincipalName
      - identifier: Name
        columnName: InitiatingAccountName
      - identifier: UPNSuffix
        columnName: InitiatingAccountUPNSuffix
  - entityType: Account
    fieldMappings:
      - identifier: AadUserId
        columnName: InitiatingAadUserId
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: InitiatingIPAddress
  - entityType: CloudApplication
    fieldMappings:
      - identifier: AppId
        columnName: InitiatingAppId
     

Required Data Sources

Sentinel TableNotes
AuditLogsEnsure this data connector is enabled

MITRE ATT&CK Context

References

False Positive Guidance

Original source: https://github.com/Azure/Azure-Sentinel/blob/main/Detections/AuditLogs/ConditionalAccessPolicyModifiedbyNewUser.yaml