Query Details

Foundry - Off-hours or anomalous-geo agent activity

Foundry Off Hours Or Geo Anomaly

Query

// Business hours expressed in UTC. Leave allowedCountries empty to
// disable the geo check (off-hours only).
let businessStart = 7;
let businessEnd = 20;
let allowedCountries = dynamic([]);
AppDependencies
| where isnotempty(Properties["gen_ai.agent.name"])
| 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"]),
    Country   = tostring(column_ifexists("ClientCountryOrRegion", "")),
    City      = tostring(column_ifexists("ClientCity", "")),
    SrcIp     = tostring(column_ifexists("ClientIP", ""))
| extend Hour = hourofday(TimeGenerated)
| extend
    OffHours     = Hour < businessStart or Hour >= businessEnd,
    AnomalousGeo = array_length(allowedCountries) > 0
                   and isnotempty(Country)
                   and not(set_has_element(allowedCountries, Country))
| where OffHours or AnomalousGeo
| summarize
    Runs       = count(),
    Countries  = make_set(Country, 20),
    Cities     = make_set(City, 20),
    SrcIps     = make_set(SrcIp, 20),
    OffHoursRuns   = countif(OffHours),
    AnomalousGeoRuns = countif(AnomalousGeo),
    FirstSeen  = min(TimeGenerated),
    LastSeen   = max(TimeGenerated)
    by Agent, Model, ProjectId, ConvId
| extend AccountName = iff(isempty(Agent), "unknown-agent", Agent)
| extend SrcIpAddr = tostring(SrcIps[0])
| project
    LastSeen, AccountName, Agent, Model, ProjectId, ConvId,
    Runs, OffHoursRuns, AnomalousGeoRuns, Countries, Cities,
    SrcIpAddr, FirstSeen
| order by LastSeen desc

Explanation

This query is designed to detect unusual activity related to the Foundry or Agent Service. It identifies instances where these services are accessed outside of normal business hours or from unexpected geographic locations. This can help in spotting potential misuse, such as stolen API keys or unauthorized automated access.

Here's a simplified breakdown of the query:

  1. Business Hours and Geography: The query checks if the service runs outside of specified business hours (7 AM to 8 PM UTC) or from countries not on an approved list. If the list is empty, the geographic check is skipped.

  2. Data Source: It uses data from AppDependencies in Application Insights, focusing on specific properties like agent name, model, conversation ID, and client location details.

  3. Conditions: It flags activities as suspicious if they occur off-hours or from an anomalous geographic location.

  4. Summarization: The query summarizes the data by counting the number of runs, identifying unique countries, cities, and IP addresses involved, and noting the first and last time these activities were seen.

  5. Output: The results include details such as the agent name, model, project ID, conversation ID, number of runs, and whether they were off-hours or from anomalous locations.

  6. Alerting: If any suspicious activity is detected, an alert is triggered, and incidents are created for further investigation.

  7. Entity Mapping: The query maps the data to entities like Account, Cloud Application, and IP for better organization and analysis.

Overall, this query helps in monitoring and alerting on potentially unauthorized or suspicious access to Foundry services, aiding in early detection of security threats.

Details

David Alonso profile picture

David Alonso

Released: June 8, 2026

Tables

AppDependencies

Keywords

FoundryAgentServiceAPIKeysAbuseHTTPServerSDKGeoIPAccountCloudApplication

Operators

letisnotemptytostringcolumn_ifexistshourofdayarray_lengthset_has_elementorandnotsummarizecountmake_setcountifminmaxbyiffisemptyprojectorder bydesc

Severity

Low

Tactics

InitialAccessDefenseEvasion

MITRE Techniques

Frequency: PT1H

Period: PT1H

Actions

GitHub