Skip to content

Commit 5ed59d8

Browse files
authored
Merge pull request Azure#13286 from doredry/patch-6
Update AI Agents queries
2 parents c0d66e7 + 2f8cf8d commit 5ed59d8

19 files changed

+700
-429
lines changed

.script/tests/KqlvalidationsTests/CustomTables/AIAgentsInfo.json

Lines changed: 32 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2,108 +2,68 @@
22
"Name": "AIAgentsInfo",
33
"Properties": [
44
{
5-
"name": "Timestamp",
6-
"type": "Datetime"
5+
"Name": "Timestamp",
6+
"Type": "DateTime"
77
},
88
{
9-
"name": "AIAgentId",
10-
"type": "String"
9+
"Name": "AIAgentId",
10+
"Type": "String"
1111
},
1212
{
13-
"name": "AIAgentName",
14-
"type": "String"
13+
"Name": "AIAgentName",
14+
"Type": "String"
1515
},
1616
{
17-
"name": "AgentCreationTime",
18-
"type": "Datetime"
17+
"Name": "AgentStatus",
18+
"Type": "String"
1919
},
2020
{
21-
"name": "CreatorAccountUpn",
22-
"type": "String"
21+
"Name": "AgentCreationTime",
22+
"Type": "DateTime"
2323
},
2424
{
25-
"name": "OwnerAccountUpns",
26-
"type": "String"
25+
"Name": "CreatorAccountUpn",
26+
"Type": "String"
2727
},
2828
{
29-
"name": "LastModifiedByUpn",
30-
"type": "String"
29+
"Name": "OwnerAccountUpns",
30+
"Type": "String"
3131
},
3232
{
33-
"name": "LastModifiedTime",
34-
"type": "Datetime"
33+
"Name": "UserAuthenticationType",
34+
"Type": "String"
3535
},
3636
{
37-
"name": "LastPublishedTime",
38-
"type": "Datetime"
37+
"Name": "AuthenticationTrigger",
38+
"Type": "String"
3939
},
4040
{
41-
"name": "AgentDescription",
42-
"type": "String"
41+
"Name": "AgentToolsDetails",
42+
"Type": "Dynamic"
4343
},
4444
{
45-
"name": "AgentStatus",
46-
"type": "String"
45+
"Name": "AgentTopicsDetails",
46+
"Type": "Dynamic"
4747
},
4848
{
49-
"name": "KnowledgeDetails",
50-
"type": "Dynamic"
49+
"Name": "AccessControlPolicy",
50+
"Type": "String"
5151
},
5252
{
53-
"name": "AgentActionTriggers",
54-
"type": "String"
53+
"Name": "LastModifiedTime",
54+
"Type": "DateTime"
5555
},
5656
{
57-
"name": "RawAgentInfo",
58-
"type": "Dynamic"
57+
"Name": "RawAgentInfo",
58+
"Type": "Dynamic"
5959
},
6060
{
61-
"name": "UserAuthenticationType",
62-
"type": "String"
61+
"Name": "EnvironmentId",
62+
"Type": "String"
6363
},
6464
{
65-
"name": "AuthenticationTrigger",
66-
"type": "String"
67-
},
68-
{
69-
"name": "AccessControlPolicy",
70-
"type": "String"
71-
},
72-
{
73-
"name": "AuthorizedSecurityGroupIds",
74-
"type": "Dynamic"
75-
},
76-
{
77-
"name": "AgentTopicsDetails",
78-
"type": "Dynamic"
79-
},
80-
{
81-
"name": "AgentToolsDetails",
82-
"type": "Dynamic"
83-
},
84-
{
85-
"name": "EnvironmentId",
86-
"type": "String"
87-
},
88-
{
89-
"name": "Platform",
90-
"type": "String"
91-
},
92-
{
93-
"name": "TenantId",
94-
"type": "String"
95-
},
96-
{
97-
"name": "Type",
98-
"type": "String"
99-
},
100-
{
101-
"name": "SourceSystem",
102-
"type": "String"
103-
},
104-
{
105-
"name": "TimeGenerated",
106-
"type": "Datetime"
65+
"Name": "IsGenerativeOrchestrationEnabled",
66+
"Type": "Boolean"
10767
}
10868
]
10969
}
Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,36 @@
1-
id: 9e4f8a1b-2c3d-4e5f-6a7b-8c9d0e1f2a3b
2-
name: AI Agents - Email AI-Controlled Inputs
3-
description: |
4-
'Identifies AI agents configured to send emails with AI-controlled inputs that may contain sensitive or inappropriate content.
5-
This configuration poses security risks as AI-generated content may include unintended information disclosure, hallucinations,
6-
or other content that should be reviewed before external transmission.'
7-
requiredDataConnectors: []
8-
tactics:
9-
- Exfiltration
10-
- Impact
11-
relevantTechniques:
12-
- T1041
13-
- T1565
14-
query: |
15-
//Find agents with email sending tool via microsoft 365 connector, where the input parameters of the inputs are populated by generative orchestrator
16-
AIAgentsInfo
17-
| summarize arg_max(Timestamp, *) by AIAgentId
18-
| where AgentStatus != "Deleted"
19-
| extend Config = tostring(todynamic(RawAgentInfo).Bot.Attributes.configuration)
20-
| parse Config with * "\"GenerativeActionsEnabled\":" GenerativeActionsEnabled:boolean *
21-
| where GenerativeActionsEnabled
22-
| mvexpand Action = AgentToolsDetails
23-
| extend OperationId = tostring(Action.action.operationId), ActionName = tostring(Action.modelDisplayName), Action
24-
| where OperationId == "SendEmailV2"
25-
| where isempty(Action.inputs) //All inputs are populated by Orchestrator
26-
| project-reorder AgentCreationTime ,AIAgentId, AIAgentName, AgentStatus, CreatorAccountUpn, OwnerAccountUpns, ActionName
27-
| extend AccountCustomEntity = CreatorAccountUpn
28-
| extend HostCustomEntity = AIAgentName
29-
entityMappings:
30-
- entityType: Account
31-
fieldMappings:
32-
- identifier: FullName
33-
columnName: CreatorAccountUpn
34-
- entityType: Host
35-
fieldMappings:
36-
- identifier: HostName
37-
columnName: AIAgentName
38-
version: 1.0.0
1+
id: 9e4f8a1b-2c3d-4e5f-6a7b-8c9d0e1f2a3b
2+
name: AI Agents - Sending email to AI controlled input values
3+
description: |
4+
This query identifies Copilot Studio AI agents using generative orchestration to send emails
5+
via the Outlook connector where all action input values are populated dynamically by the orchestrator.
6+
This configuration is risky because if an attacker successfully performs a prompt injection (XPIA) attack,
7+
the agent could be manipulated to exfiltrate sensitive data to arbitrary recipients.
8+
Recommended Action: Confirm with the agent owner whether this behavior is required and understand the business justification.
9+
If feasible, hard-code the recipient address in the email action or apply strict validation to limit misuse.
10+
requiredDataConnectors: []
11+
tactics:
12+
- Exfiltration
13+
- Impact
14+
relevantTechniques:
15+
- T1041
16+
- T1565
17+
query: |
18+
AIAgentsInfo
19+
| summarize arg_max(Timestamp, *) by AIAgentId
20+
| where AgentStatus != "Deleted"
21+
| where IsGenerativeOrchestrationEnabled
22+
| mvexpand Action = AgentToolsDetails
23+
| extend OperationId = tostring(Action.action.operationId), ActionName = tostring(Action.modelDisplayName), Action
24+
| where OperationId == "SendEmailV2"
25+
| where isempty(Action.inputs)
26+
| project-reorder AgentCreationTime ,AIAgentId, AIAgentName, AgentStatus, CreatorAccountUpn, OwnerAccountUpns, ActionName
27+
entityMappings:
28+
- entityType: Account
29+
fieldMappings:
30+
- identifier: FullName
31+
columnName: CreatorAccountUpn
32+
- entityType: Host
33+
fieldMappings:
34+
- identifier: HostName
35+
columnName: AIAgentName
36+
version: 1.0.0
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
id: 0d5e9f1a-2b3c-4d5e-6f7a-8b9c0d1e2f3a
2+
name: AI Agents - Sending email to external mailboxes
3+
description: |
4+
This query identifies Copilot Studio AI agents configured to send emails to external mailboxes (outside the organization`s domains).
5+
Such configurations can lead to sensitive or internal data being exfiltrated beyond organizational boundaries, creating compliance and security risks.
6+
Attackers could exploit this to leak confidential information or use compromised agents as a channel for data exfiltration.
7+
Recommended Action: Verify with the agent owner whether sending emails externally is necessary for the business scenario.
8+
Confirm what data is being sent and ensure the external domain is authorized to receive it. If not required, remove or restrict this capability.
9+
requiredDataConnectors: []
10+
tactics:
11+
- Exfiltration
12+
relevantTechniques:
13+
- T1041
14+
query: |
15+
let OrgDomains =
16+
IdentityInfo
17+
| extend domains = tostring(split(AccountUPN, "@")[1])
18+
| distinct domains;
19+
let SendOps = dynamic([
20+
"SendEmailV2", // Office 365 Outlook
21+
"SharedMailboxSendEmailV2",// Office 365 Outlook
22+
"| w", // Outlook.com
23+
"SendEmailV2", // Gmail
24+
"SendEmailV3", // SMTP
25+
"SendEmailV3", // Mail
26+
"SendEmailGAVersion", // Azure Communication Email
27+
"PostAntTextEmail", // Ant Text Automation
28+
"SendEmailV4" // SendGrid
29+
]);
30+
let FromActions =
31+
AIAgentsInfo
32+
| summarize arg_max(Timestamp, *) by AIAgentId
33+
| where AgentStatus != "Deleted"
34+
| mv-expand ActionDetail = todynamic(AgentToolsDetails)
35+
| where tostring(ActionDetail.action.operationId) in~ (SendOps)
36+
| mv-expand ActionInput = ActionDetail.inputs
37+
| where tostring(ActionInput.propertyName) == "To"
38+
| extend ToAddress = tostring(ActionInput.value.literalValue)
39+
| extend Domain = tostring(split(ToAddress, "@")[1]), MailConeector = tostring(ActionDetail.action.operationId), source = "AgentToolsDetails"
40+
| where isnotempty(Domain) and Domain !in (OrgDomains)
41+
| project-reorder AgentCreationTime, AIAgentId, AIAgentName, AgentStatus, CreatorAccountUpn, OwnerAccountUpns, ToAddress, Domain, source, MailConeector;
42+
let FromTopics =
43+
AIAgentsInfo
44+
| summarize arg_max(Timestamp, *) by AIAgentId
45+
| where AgentStatus != "Deleted"
46+
| mv-expand TopicDetail = todynamic(AgentTopicsDetails)
47+
| mv-expand TopicAction = TopicDetail.beginDialog.actions
48+
| where tostring(TopicAction.operationId) in~ (SendOps)
49+
| extend ToAddress = tostring(coalesce(TopicAction.input.binding.To.literalValue, TopicAction.input.binding['to'].literalValue))
50+
| extend Domain = tostring(split(ToAddress, "@")[1]), MailConeector = tostring(TopicAction.operationId), source = "AgentTopicsDetails"
51+
| where isnotempty(Domain) and Domain !in (OrgDomains)
52+
| project-reorder AgentCreationTime, AIAgentId, AIAgentName, AgentStatus, CreatorAccountUpn, OwnerAccountUpns, ToAddress, Domain, source, MailConeector;
53+
FromActions
54+
| union FromTopics
55+
| project-reorder AgentCreationTime, AIAgentId, AIAgentName, AgentStatus, CreatorAccountUpn, OwnerAccountUpns
56+
entityMappings:
57+
- entityType: Account
58+
fieldMappings:
59+
- identifier: FullName
60+
columnName: CreatorAccountUpn
61+
- entityType: Host
62+
fieldMappings:
63+
- identifier: HostName
64+
columnName: AIAgentName
65+
version: 1.0.0
Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,50 @@
1-
id: 8f0a7b1c-2d3e-4f5a-6b7c-8d9e0f1a2b3c
2-
name: AI Agents - Published Generative Orchestration without Instructions
3-
description: |
4-
'Identifies published AI agents with generative orchestration that lack configured instructions. This may present
5-
a risk to the agent and heighten the likelihood of the agent being influenced to deviate from the intended course
6-
of action through prompt injection attacks. Organizations should ensure proper instructions are configured.'
7-
requiredDataConnectors: []
8-
tactics:
9-
- Impact
10-
- DefenseEvasion
11-
relevantTechniques:
12-
- T1499
13-
- T1562
14-
query: |
15-
AIAgentsInfo
16-
| summarize arg_max(Timestamp, *) by AIAgentId
17-
| where AgentStatus != "Deleted"
18-
| extend Config = tostring(todynamic(RawAgentInfo).Bot.Attributes.configuration)
19-
| parse Config with * "\"GenerativeActionsEnabled\":" GenerativeActionsEnabled:boolean *
20-
| where GenerativeActionsEnabled
21-
| extend BotComponents = todynamic(RawAgentInfo).BotComponents
22-
| mv-expand BotComponent = BotComponents
23-
| where BotComponent has "GptComponentMetadata"
24-
| where BotComponent.FormattedValues.componenttype == "Custom GPT"
25-
| extend InstructionsRaw = tostring(BotComponent.Attributes.data), AIAgentName
26-
| where InstructionsRaw has "instructions"
27-
| where BotComponent.Attributes.schemaname endswith ".gpt.default"
28-
| extend DisplayNamePos = indexof(InstructionsRaw, "displayName", indexof(InstructionsRaw, "instructions:") + strlen("instructions:"))
29-
| extend CapabilitiesPos = indexof(InstructionsRaw, "gptCapabilities", indexof(InstructionsRaw, "instructions:") + strlen("instructions:"))
30-
| extend InstructionsStart = indexof(InstructionsRaw, "instructions:") + strlen("instructions:")
31-
| extend InstructionsEnd = iif(
32-
DisplayNamePos != -1 and CapabilitiesPos != -1,
33-
iif(DisplayNamePos < CapabilitiesPos, DisplayNamePos, CapabilitiesPos),
34-
iif(DisplayNamePos != -1, DisplayNamePos,
35-
iif(CapabilitiesPos != -1, CapabilitiesPos, strlen(InstructionsRaw)))
36-
)
37-
| extend Instructions = substring(InstructionsRaw, InstructionsStart, InstructionsEnd - InstructionsStart)
38-
| where CapabilitiesPos == 43 and CapabilitiesPos == InstructionsEnd
39-
| project-away DisplayNamePos, CapabilitiesPos, InstructionsStart, InstructionsEnd
40-
| project-reorder AgentCreationTime, AIAgentId, AIAgentName, AgentStatus, CreatorAccountUpn, OwnerAccountUpns
41-
| extend AccountCustomEntity = CreatorAccountUpn
42-
| extend HostCustomEntity = AIAgentName
43-
entityMappings:
44-
- entityType: Account
45-
fieldMappings:
46-
- identifier: FullName
47-
columnName: CreatorAccountUpn
48-
- entityType: Host
49-
fieldMappings:
50-
- identifier: HostName
51-
columnName: AIAgentName
52-
version: 1.0.0
1+
id: 8f0a7b1c-2d3e-4f5a-6b7c-8d9e0f1a2b3c
2+
name: AI Agents - Published Generative Orchestration without Instructions
3+
description: |
4+
This query identifies Copilot Studio AI agents that are published with generative orchestration enabled but lack configured instructions.
5+
Missing instructions increase the risk of prompt injection attacks, where malicious input can influence the agent to deviate from its intended behavior.
6+
Without clear guidance, the agent may respond unpredictably or expose sensitive data.
7+
Recommended Action: Ensure all generative orchestration components have well-defined instructions that specify the agent`s purpose, boundaries, and allowed actions.
8+
Regularly review and update instructions to maintain security and prevent misuse.
9+
requiredDataConnectors: []
10+
tactics:
11+
- Impact
12+
- DefenseEvasion
13+
relevantTechniques:
14+
- T1499
15+
- T1562
16+
query: |
17+
AIAgentsInfo
18+
| summarize arg_max(Timestamp, *) by AIAgentId
19+
| where AgentStatus != "Deleted"
20+
| where IsGenerativeOrchestrationEnabled
21+
| extend BotComponents = todynamic(RawAgentInfo).BotComponents
22+
| mv-expand BotComponent = BotComponents
23+
| where BotComponent has "GptComponentMetadata"
24+
| where BotComponent.FormattedValues.componenttype == "Custom GPT"
25+
| extend InstructionsRaw = tostring(BotComponent.Attributes.data), AIAgentName
26+
| where InstructionsRaw has "instructions"
27+
| where BotComponent.Attributes.schemaname endswith ".gpt.default"
28+
| extend DisplayNamePos = indexof(InstructionsRaw, "displayName", indexof(InstructionsRaw, "instructions:") + strlen("instructions:"))
29+
| extend CapabilitiesPos = indexof(InstructionsRaw, "gptCapabilities", indexof(InstructionsRaw, "instructions:") + strlen("instructions:"))
30+
| extend InstructionsStart = indexof(InstructionsRaw, "instructions:") + strlen("instructions:")
31+
| extend InstructionsEnd = iif(
32+
DisplayNamePos != -1 and CapabilitiesPos != -1,
33+
iif(DisplayNamePos < CapabilitiesPos, DisplayNamePos, CapabilitiesPos),
34+
iif(DisplayNamePos != -1, DisplayNamePos,
35+
iif(CapabilitiesPos != -1, CapabilitiesPos, strlen(InstructionsRaw)))
36+
)
37+
| extend Instructions = substring(InstructionsRaw, InstructionsStart, InstructionsEnd - InstructionsStart)
38+
| where isempty(Instructions)
39+
| project-away DisplayNamePos, CapabilitiesPos, InstructionsStart, InstructionsEnd
40+
| project-reorder AgentCreationTime, AIAgentId, AIAgentName, AgentStatus, CreatorAccountUpn, OwnerAccountUpns
41+
entityMappings:
42+
- entityType: Account
43+
fieldMappings:
44+
- identifier: FullName
45+
columnName: CreatorAccountUpn
46+
- entityType: Host
47+
fieldMappings:
48+
- identifier: HostName
49+
columnName: AIAgentName
50+
version: 1.0.0

0 commit comments

Comments
 (0)