This hunt detects adversaries who have escalated the scope of previously restricted AI agents to organization-wide access, potentially leveraging their integrated MCP servers and declared tools to exfiltrate sensitive data or execute unauthorized actions across the tenant. Proactively hunting for this behavior in Azure Sentinel is critical because such rapid permission expansion often bypasses standard change management controls, creating a high-risk window where compromised agents can silently pivot laterally before detection.
let lookback = 14d;
let recent = 2d;
let IdentityIdtoUPN = materialize(
IdentityInfo
| extend ResolvedAccountUpn = tostring(column_ifexists("AccountUpn", column_ifexists("AccountUPN", ""))),
IdentityTimestamp = todatetime(column_ifexists("Timestamp", column_ifexists("TimeGenerated", datetime(null))))
| where IdentityTimestamp >= ago(lookback)
| where isnotempty(AccountObjectId) and isnotempty(ResolvedAccountUpn)
| summarize arg_max(IdentityTimestamp, ResolvedAccountUpn) by AccountObjectId
| project AccountObjectId = tostring(AccountObjectId), AccountUpn = ResolvedAccountUpn);
let CurrentState =
AgentsInfo
| where Timestamp > ago(recent)
| summarize arg_max(Timestamp, *) by AgentId
| where LifecycleStatus != "Deleted"
| where set_has_element(coalesce(SharedWith, dynamic([])), "*")
| extend McpServerCount = array_length(coalesce(McpServers, dynamic([]))),
DeclaredToolCount = array_length(coalesce(DeclaredTools, dynamic([])))
| project AgentId, Timestamp, Name, Platform, CreatedDateTime, Owners,
SharedWith, McpServerCount, DeclaredToolCount;
let BaselineState =
AgentsInfo
| where Timestamp between (ago(lookback) .. ago(recent))
| where LifecycleStatus != "Deleted"
| summarize arg_max(Timestamp, *) by AgentId
| where not(set_has_element(coalesce(SharedWith, dynamic([])), "*"))
| project AgentId, PreviousTimestamp = Timestamp, PreviousSharedWith = SharedWith;
CurrentState
| join kind=inner BaselineState on AgentId
| extend HasElevatedCapabilities = McpServerCount > 0 or DeclaredToolCount > 0
| extend OwnerIds = iff(array_length(coalesce(Owners, dynamic([]))) > 0, Owners, dynamic([""]))
| mv-expand OwnerId = OwnerIds to typeof(string)
| join kind=leftouter IdentityIdtoUPN on $left.OwnerId == $right.AccountObjectId
| project-rename OwnerUpn = AccountUpn
| extend OwnerAccountName = tostring(split(OwnerUpn, "@")[0]),
OwnerAccountUPNSuffix = tostring(split(OwnerUpn, "@")[1])
| project Timestamp, PreviousTimestamp, AgentId, Name, Platform, CreatedDateTime,
PreviousSharedWith, SharedWith, McpServerCount, DeclaredToolCount,
HasElevatedCapabilities, OwnerId, OwnerUpn, OwnerAccountName, OwnerAccountUPNSuffix
| sort by HasElevatedCapabilities desc, Timestamp desc
id: dbdba9cc-d7a0-434d-9c3d-82d2203a79fd
name: AI Agents - Sharing expanded to organization-wide
description: |
Identifies existing AI agents that were restricted in the baseline snapshot and are now shared organization-wide. Prioritize agents with MCP servers or declared tools for review. Run within 2 days of a change to retain coverage.
requiredDataConnectors: []
tactics: []
relevantTechniques: []
query: |
let lookback = 14d;
let recent = 2d;
let IdentityIdtoUPN = materialize(
IdentityInfo
| extend ResolvedAccountUpn = tostring(column_ifexists("AccountUpn", column_ifexists("AccountUPN", ""))),
IdentityTimestamp = todatetime(column_ifexists("Timestamp", column_ifexists("TimeGenerated", datetime(null))))
| where IdentityTimestamp >= ago(lookback)
| where isnotempty(AccountObjectId) and isnotempty(ResolvedAccountUpn)
| summarize arg_max(IdentityTimestamp, ResolvedAccountUpn) by AccountObjectId
| project AccountObjectId = tostring(AccountObjectId), AccountUpn = ResolvedAccountUpn);
let CurrentState =
AgentsInfo
| where Timestamp > ago(recent)
| summarize arg_max(Timestamp, *) by AgentId
| where LifecycleStatus != "Deleted"
| where set_has_element(coalesce(SharedWith, dynamic([])), "*")
| extend McpServerCount = array_length(coalesce(McpServers, dynamic([]))),
DeclaredToolCount = array_length(coalesce(DeclaredTools, dynamic([])))
| project AgentId, Timestamp, Name, Platform, CreatedDateTime, Owners,
SharedWith, McpServerCount, DeclaredToolCount;
let BaselineState =
AgentsInfo
| where Timestamp between (ago(lookback) .. ago(recent))
| where LifecycleStatus != "Deleted"
| summarize arg_max(Timestamp, *) by AgentId
| where not(set_has_element(coalesce(SharedWith, dynamic([])), "*"))
| project AgentId, PreviousTimestamp = Timestamp, PreviousSharedWith = SharedWith;
CurrentState
| join kind=inner BaselineState on AgentId
| extend HasElevatedCapabilities = McpServerCount > 0 or DeclaredToolCount > 0
| extend OwnerIds = iff(array_length(coalesce(Owners, dynamic([]))) > 0, Owners, dynamic([""]))
| mv-expand OwnerId = OwnerIds to typeof(string)
| join kind=leftouter IdentityIdtoUPN on $left.OwnerId == $right.AccountObjectId
| project-rename OwnerUpn = AccountUpn
| extend OwnerAccountName = tostring(split(OwnerUpn, "@")[0]),
OwnerAccountUPNSuffix = tostring(split(OwnerUpn, "@")[1])
| project Timestamp, PreviousTimestamp, AgentId, Name, Platform, CreatedDateTime,
PreviousSharedWith, SharedWith, McpServerCount, DeclaredToolCount,
HasElevatedCapabilities, OwnerId, OwnerUpn, OwnerAccountName, OwnerAccountUPNSuffix
| sort by HasElevatedCapabilities desc, Timestamp desc
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: OwnerAccountName
- identifier: UPNSuffix
columnName: OwnerA
| Sentinel Table | Notes |
|---|---|
IdentityInfo | Ensure this data connector is enabled |
Here are 5 specific false positive scenarios for the “AI Agents - Sharing expanded to organization-wide” detection rule, including suggested filters and exclusions:
Scheduled Compliance Audit Agent Updates
organization-wide to ingest data from all regional sub-tenants before reverting changes, triggering the alert during the 48-hour window.Comp-Audit- or Qtrly-Review-, and filter out events where the modification timestamp aligns with known scheduled maintenance windows (e.g., Sundays between 02:00–04:00 UTC).MCP Server Provisioning for New Tool Integration
department-specific to organization-wide to ensure immediate visibility across all security clusters.MCP_Server_ID fields in their metadata within the last 24 hours, specifically targeting tools named ThreatIntel-MCP, SIEM-Connector-MCP, or similar standard integration names.Global Knowledge Base Refresh via Admin Task