Query Details
id: 4d5e6f70-1313-4312-9212-0123456789e2
name: Foundry - URL / domain / IP matched against threat intelligence
description: |
Extracts URLs (and their hosts / IPs) from Foundry / Agent Service
conversation content - both user input (gen_ai.input.messages) and agent
output (gen_ai.output.messages) - and correlates them against active
Microsoft Sentinel threat-intelligence indicators. A match means the
agent either received or emitted a known malicious / suspicious URL,
domain or IP, which can indicate a phishing lure fed to the agent, a
poisoned RAG / knowledge source, or a corrupted agent surfacing attacker
infrastructure. This is the high-fidelity companion to
FoundrySuspiciousUrlInContent (which is heuristic): here the verdict
comes from the TI feed.
Joins against the modern ThreatIntelIndicators table (network observable
types url:value / domain-name:value / ipv4-addr:value / ipv6-addr:value)
and only considers active, non-revoked, in-date indicators. Reads agent
text from AppDependencies (requires
AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED).
severity: High
requiredDataConnectors:
- connectorId: ApplicationInsights
dataTypes:
- AppDependencies
- connectorId: ThreatIntelligence
dataTypes:
- ThreatIntelIndicators
queryFrequency: PT1H
queryPeriod: P14D
triggerOperator: gt
triggerThreshold: 0
enabled: true
tactics:
- CommandAndControl
- InitialAccess
relevantTechniques:
- T1071
- T1566
query: |
let dt_lookBack = 1h;
let ioc_lookBack = 14d;
let networkIocTypes = dynamic(["url:value", "domain-name:value", "ipv4-addr:value", "ipv6-addr:value"]);
let TI =
ThreatIntelIndicators
| where TimeGenerated > ago(ioc_lookBack)
| where IsActive == true and Revoked == false
| where ObservableKey in (networkIocTypes)
| where isempty(ValidUntil) or ValidUntil > now()
| summarize arg_max(TimeGenerated, *) by IndicatorId = Id
| extend IOC = tolower(ObservableValue)
| where isnotempty(IOC);
let Spans =
AppDependencies
| where TimeGenerated > ago(dt_lookBack)
| where isnotempty(Properties["gen_ai.input.messages"]) or isnotempty(Properties["gen_ai.output.messages"])
| extend
Agent = tostring(Properties["gen_ai.agent.name"]),
Model = tostring(Properties["gen_ai.request.model"]),
ConvId = tostring(Properties["gen_ai.conversation.id"]),
ProjectId = tostring(Properties["microsoft.foundry.project.id"]),
Input = tostring(Properties["gen_ai.input.messages"]),
Output = tostring(Properties["gen_ai.output.messages"]),
SrcIp = tostring(column_ifexists("ClientIP", ""));
let FromInput = Spans | where isnotempty(Input) | extend Direction = "UserPrompt", Text = Input;
let FromOutput = Spans | where isnotempty(Output) | extend Direction = "AgentResponse", Text = Output;
let Content =
union FromInput, FromOutput
| mv-expand Url = extract_all(@"(https?://[^\s\)\]\}""'<>]+)", Text) to typeof(string)
| extend
Url = tolower(Url),
Host = tolower(tostring(extract(@"https?://([^/:\s]+)", 1, Url)))
| mv-expand IOC = pack_array(Url, Host) to typeof(string)
| where isnotempty(IOC);
Content
| join kind=inner TI on IOC
| extend AccountName = iff(isempty(Agent), "unknown-agent", Agent)
| project
TimeGenerated, Direction, AccountName, Agent, Model, ProjectId, ConvId,
MatchedIOC = IOC, ObservableKey, Confidence,
ThreatType = tostring(todynamic(Data).indicator_types[0]),
Description = tostring(todynamic(Data).description),
Url, Host, SrcIp
| order by TimeGenerated desc
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- entityType: CloudApplication
fieldMappings:
- identifier: Name
columnName: Model
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
- entityType: IP
fieldMappings:
- identifier: Address
columnName: SrcIp
eventGroupingSettings:
aggregationKind: SingleAlert
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT6H
matchingMethod: Selected
groupByEntities:
- Account
- URL
groupByAlertDetails: []
groupByCustomDetails: []
version: 1.0.0
kind: Scheduled
tags:
- Sentinel-As-Code
- Custom
- Foundry
- AI
- ThreatIntelligence
- MaliciousUrl
This query is designed to detect potentially malicious URLs, domains, or IP addresses that are involved in interactions with an AI agent. Here's a simplified breakdown of what it does:
Purpose: The query checks if any URLs, domains, or IPs extracted from AI agent conversations match known threat intelligence indicators. This helps identify if the AI agent is interacting with or being targeted by malicious entities.
Data Sources: It uses data from two main sources:
Process:
Output: If a match is found, it provides details such as the time of the event, the direction of the conversation (user input or agent response), the agent's name, the model used, and the matched threat intelligence data.
Severity and Alerts: The severity of the alert is marked as high, and it triggers an alert if any matches are found. It also creates incidents for further investigation.
Frequency: The query runs every hour and looks back over the past 14 days for threat intelligence data.
Use Case: This is useful for identifying potential security threats like phishing attempts or compromised AI agents interacting with malicious infrastructure.
Overall, this query helps in monitoring and securing AI agent interactions by leveraging threat intelligence data to detect and alert on suspicious activities.

David Alonso
Released: June 8, 2026
Tables
Keywords
Operators