Query Details
id: a1b2c3d4-1015-4a11-9c01-0123456789b5
name: Copilot Studio - Suspicious or phishing URL in prompt or response
description: |
Raises an incident when a URL with phishing / malicious characteristics
appears in a Copilot Studio conversation - either sent by the user
(BotMessageReceived) or emitted by the agent (BotMessageSend). Flags
raw-IP URLs, punycode / IDN homograph hosts (xn--), known URL shorteners,
credential-bait paths (login / verify / reset-password / wallet), and
risky / look-alike TLDs. Covers the Defender for Cloud "Phishing URL
shared", "Phishing attempt detected", and "Corrupted AI directed a
phishing attempt" alert family from your own telemetry.
Reads AppEvents text (requires "Log sensitive properties" on the agent's
Application Insights settings). Heuristic by design - treat as a triage
signal, not a verdict. To raise fidelity, join ClientIP / host against a
threat-intel watchlist or the ThreatIntelligenceIndicator table.
severity: High
requiredDataConnectors:
- connectorId: ApplicationInsights
dataTypes:
- AppEvents
queryFrequency: PT1H
queryPeriod: PT1H
triggerOperator: gt
triggerThreshold: 0
enabled: true
tactics:
- InitialAccess
- Execution
relevantTechniques:
- T1566
- T1204
query: |
let shorteners = dynamic(["bit.ly","tinyurl.com","t.co","goo.gl","ow.ly","is.gd","buff.ly","rb.gy","cutt.ly","rebrand.ly"]);
let baitPaths = dynamic(["login","signin","verify","secure","account","update","reset","password","wallet","seed","mfa","authenticate","confirm"]);
let riskyTlds = dynamic([".zip",".mov",".xyz",".top",".click",".country",".gq",".tk",".ml",".cf",".ga",".rest",".quest"]);
AppEvents
| where Name in ("BotMessageReceived", "BotMessageSend")
| extend
ConvId = tostring(Properties["conversationId"]),
ChannelId = tostring(Properties["channelId"]),
Direction = iff(Name == "BotMessageReceived", "UserPrompt", "AgentResponse"),
Text = tostring(Properties["text"])
| where isnotempty(Text)
| mv-expand Url = extract_all(@"(https?://[^\s\)\]\}""'<>]+)", Text) to typeof(string)
| extend
Host = tolower(tostring(extract(@"https?://([^/:\s]+)", 1, Url))),
Path = tolower(tostring(extract(@"https?://[^/]+(/[^\s]*)?", 1, Url)))
| extend Tld = tolower(tostring(extract(@"(\.[a-z]+)$", 1, Host)))
| extend
RawIpHost = Host matches regex @"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$",
Punycode = Host contains "xn--",
Shortener = Host in (shorteners),
RiskyTld = set_has_element(riskyTlds, Tld),
BaitPath = Path has_any (baitPaths),
AtTrick = Url matches regex @"https?://[^/\s]+@"
| extend RiskScore = toint(RawIpHost) + toint(Punycode) + toint(Shortener)
+ toint(RiskyTld) + toint(BaitPath) + toint(AtTrick)
| where RiskScore > 0
| extend Reasons = trim(",", strcat(
iff(RawIpHost, "RawIP,", ""), iff(Punycode, "Punycode,", ""),
iff(Shortener, "Shortener,", ""), iff(RiskyTld, "RiskyTLD,", ""),
iff(BaitPath, "CredentialBaitPath,", ""), iff(AtTrick, "UserinfoTrick,", "")))
| extend AccountName = iff(isempty(UserId), "unknown-agent", UserId)
| project
TimeGenerated, Direction, RiskScore, Reasons, AccountName, ConvId, ChannelId,
Url = substring(Url, 0, 512), Host, SessionId, ClientIP, AppVersion
| order by RiskScore desc, TimeGenerated desc
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: AccountName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: ClientIP
- entityType: URL
fieldMappings:
- identifier: Url
columnName: Url
eventGroupingSettings:
aggregationKind: SingleAlert
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT6H
matchingMethod: Selected
groupByEntities:
- Account
groupByAlertDetails: []
groupByCustomDetails: []
version: 1.0.0
kind: Scheduled
tags:
- Sentinel-As-Code
- Custom
- CopilotStudio
- AI
- Phishing
- MaliciousUrl
This query is designed to detect suspicious or phishing URLs in conversations within Copilot Studio, a conversational AI platform. Here's a simplified breakdown of what it does:
Purpose: The query raises an alert when a URL with potentially malicious characteristics is detected in a conversation. This could be a URL sent by a user or generated by the AI agent.
Detection Criteria: It looks for URLs that match certain suspicious patterns, including:
Data Source: It analyzes text from AppEvents, which requires enabling "Log sensitive properties" in Application Insights settings.
Risk Scoring: Each URL is assigned a risk score based on the presence of these suspicious characteristics. If the score is greater than zero, the URL is flagged.
Output: The query outputs details such as the time the URL was generated, the direction of the message (user or agent), the risk score, reasons for the score, account name, conversation ID, channel ID, and the URL itself.
Alert Configuration: If a suspicious URL is detected, an incident is created. Alerts are grouped by account, and incidents can be reopened if similar activity is detected within a six-hour lookback period.
Frequency: The query runs every hour and checks for any new suspicious URLs within the past hour.
Severity and Tactics: The severity of the alert is marked as high, and it relates to tactics like Initial Access and Execution, aligning with techniques T1566 (Phishing) and T1204 (User Execution).
Overall, this query acts as a triage tool to identify potential phishing attempts in AI-driven conversations, helping security teams to take further action if needed.

David Alonso
Released: June 8, 2026
Tables
Keywords
Operators