↳ GitHub sourceAnalytics ruleHigh

Canary alerts to incidents

Description

Creates Microsoft Sentinel incidents from Thinkst Canary alerts.
Rule type
NRT
Version
1.0.2
Declared status
Available

Declared MITRE coverage

Declared sources

Metadata from the source file. No dependencies inferred from KQL.

Connectors

Data types

KQL query

Original query, unchanged.

ThinkstCanaryIncidents_CL
| where Description != "Canary Disconnected"
| where Description != "Canary Reconnected"
| where Description != "Canary Settings Changed"
| where Description != "Fake Location"
| where Description != "Network Settings Roll-back"
| extend EventData = todynamic(RawEvent[0])
| extend IsCanarytoken = Description contains "Canarytoken"
    or LogType startswith "16"
    or LogType startswith "17"
    or isnotempty(tostring(EventData.canarytoken))
| extend PhysicalCanaryName = coalesce(tostring(Host.name), NodeId),
    PhysicalCanaryIP = coalesce(tostring(Host.ip_address), DestinationIP, IpAddress),
    TokenMemo = iff(IsCanarytoken, substring(Memo, 0, 256), ""),
    TokenType = coalesce(tostring(EventData.kind), tostring(EventData.type)),
    TokenHostname = tostring(EventData.hostname),
    TokenTarget = substring(coalesce(tostring(EventData.url), tostring(EventData.hostname), tostring(EventData.cloned_site), tostring(EventData.original_site), tostring(EventData.generic_data), tostring(EventData.location)), 0, 512),
    TokenUsername = coalesce(tostring(EventData.windows_desktopini_access_username), tostring(EventData.ms_macro_username), tostring(EventData.cmd_user_name)),
    TokenDomain = coalesce(tostring(EventData.windows_desktopini_access_domain), tostring(EventData.cmd_machine_name)),
    TokenHost = coalesce(tostring(EventData.windows_desktopini_computer_name), tostring(EventData.cmd_computer_name), tostring(EventData.cmd_workstation), tostring(EventData.cmd_machine_name)),
    TokenSourceIP = coalesce(tostring(EventData.cmd_resolved_ip), tostring(EventData.ms_macro_ip)),
    TokenCity = coalesce(tostring(EventData.geoip.city), tostring(EventData.geoip.City), tostring(EventData.City)),
    TokenCountry = coalesce(tostring(EventData.geoip.country), tostring(EventData.geoip.country_name), tostring(EventData.geoip.Country), tostring(EventData.Country)),
    TokenContext = case(
      isnotempty(tostring(EventData.client_public_key)), strcat("WireGuard public key: ", substring(tostring(EventData.client_public_key), 0, 128), "; session: ", tostring(EventData.client_session_index)),
      isnotempty(tostring(EventData.masked_card_number)), strcat("Masked card: ", tostring(EventData.masked_card_number), "; transaction: ", tostring(EventData.transaction_amount), " ", tostring(EventData.transaction_currency), "; merchant: ", tostring(EventData.merchant)),
      isnotempty(tostring(EventData.referer)), strcat("Referrer: ", substring(tostring(EventData.referer), 0, 256)),
      ""),
    UserAgent = substring(coalesce(tostring(EventData.USERAGENT), tostring(EventData.HEADERS['user-agent']), tostring(EventData.headers['User-Agent']), tostring(EventData.headers['user-agent'])), 0, 512)
| extend ActorUsername = coalesce(tostring(EventData.USERNAME), tostring(EventData.USER), tostring(EventData.FORMDATA.username), tostring(EventData.POSTDATA.username), TokenUsername),
    ActorDomain = coalesce(tostring(EventData.DOMAIN), tostring(EventData.DOMAINNAME), TokenDomain),
    ActorHost = coalesce(TokenHost, tostring(EventData.HOSTNAME)),
    Activity = coalesce(TokenContext, TokenType, tostring(EventData.INSTANCE_NAME), tostring(EventData.FUNC_NAME), tostring(EventData.METHOD), tostring(EventData.OPCODE), tostring(EventData.COMMAND), tostring(EventData.FUNCTION), Description)
| extend SourceIP = coalesce(SourceIP, tostring(EventData.src_host), TokenSourceIP),
    SourceGeo = case(isnotempty(TokenCity) and isnotempty(TokenCountry), strcat(TokenCity, ", ", TokenCountry), isnotempty(TokenCity), TokenCity, TokenCountry),
    AssetType = iff(IsCanarytoken, "Canarytoken", "Canary"),
    AssetName = iff(IsCanarytoken, coalesce(TokenMemo, TokenTarget, TokenType, NodeId), PhysicalCanaryName),
    AssetNode = NodeId,
    AssetIP = iff(IsCanarytoken, "", PhysicalCanaryIP),
    AssetLocation = iff(IsCanarytoken, "", tostring(Host.description)),
    CanaryEntityName = iff(IsCanarytoken, "", PhysicalCanaryName),
    CanaryEntityIP = iff(IsCanarytoken, "", PhysicalCanaryIP)
| extend SourceDisplay = coalesce(SourceIP, SrcHostReverse, "unknown source")
| project TimeGenerated, Description, IncidentId, AssetType, AssetName, AssetNode,
    AssetIP, AssetLocation, FlockName, TokenMemo, TokenType, TokenTarget,
    TokenHostname, ActorUsername, ActorDomain, ActorHost, SourceGeo, SourceIP,
    SourceDisplay, SrcHostReverse, DestinationPort, Activity, UserAgent, LogType,
    EventsCount, CanaryEntityName, CanaryEntityIP

Declared entities

IPHostAccountDNS

Related content

Links established from declared identifiers and solution manifests.

Source provenance

GitHub

Displayed values come from files in Azure/Azure-Sentinel. They describe the published template, not your workspace configuration.

Source identifier
06360572-94a7-42a4-add7-58fb933b2353
Additional source files 2Solutions/ThinkstCanary/Analytic Rules/SentinelIncidentsFromThinkstCanaryAlerts.yamlsource ↗Solutions/ThinkstCanary/Data/Solution_ThinkstCanary.jsonsolution-membership ↗
GSTEP / CATALOG TRACKING

Added to catalog : 16 Sept 2026 · 05:49 UTC
Last change observed : 16 Sept 2026 · 05:49 UTC

GSTEP sync dates, separate from the source content’s publication dates.