SigninLogs — Service Account Interactive Browser Sign-In
13 SIGNIN Service Account Interactive Login
Query
// ---- Network Allowlist (exclude trusted IPs / CIDR / ranges) --------------
let _allow = materialize(union isfuzzy=true (print R="" | take 0), (_GetWatchlist('NetworkAllowlist') | project R = tostring(IPOrRange)) | where isnotempty(R));
let _allowCIDR = toscalar(_allow | where not(R matches regex @'^\d+\.\d+\.\d+\.\d+-\d+\.\d+\.\d+\.\d+$') | extend R = iff(R has '/', R, strcat(R, '/32')) | summarize make_list(R));
let _allowRange = toscalar(_allow | where R matches regex @'^\d+\.\d+\.\d+\.\d+-\d+\.\d+\.\d+\.\d+$' | summarize make_list(R));
let _ExcludeAllowlistedIPs = (T:(IPAddress:string)) {
T
| extend IPAddress = tostring(IPAddress)
| where array_length(_allowCIDR) == 0 or isnull(ipv4_is_in_any_range(IPAddress, _allowCIDR)) or not(ipv4_is_in_any_range(IPAddress, _allowCIDR))
| mv-apply _r = _allowRange to typeof(string) on (
extend _lo = tostring(split(_r,'-')[0]), _hi = tostring(split(_r,'-')[1])
| extend _inRange = ipv4_compare(IPAddress, _lo) >= 0 and ipv4_compare(IPAddress, _hi) <= 0
| summarize _anyInRange = max(toint(_inRange)))
| where isnull(_anyInRange) or _anyInRange == 0
| project-away _anyInRange
};
// ---------------------------------------------------------------------------
let serviceAccountKeywords = dynamic([
"svc", "svc-", "svc.", "-svc", "_svc",
"app-", "app_", "api-", "api_",
"bot-", "bot_", "sys-", "sys_",
"func-", "func_", "daemon", "automation",
"robot", "service_", "service-", "noreply",
"pipeline", "cicd", "ci-", "cd-"
]);
SigninLogs
| invoke _ExcludeAllowlistedIPs()
| where TimeGenerated > ago(4h)
| where ResultType == "0"
| where IsInteractive == true
| where ClientAppUsed == "Browser"
| where UserPrincipalName has_any (serviceAccountKeywords)
| project
TimeGenerated,
UserPrincipalName,
IPAddress,
Location,
AppDisplayName,
RiskLevel = RiskLevelDuringSignIn,
CAStatus = ConditionalAccessStatus,
UserAgentExplanation
This query is designed to detect suspicious activity involving service accounts and non-human identities that are performing interactive sign-ins using a web browser. Here's a simplified breakdown of what the query does:
-
Purpose: The query aims to identify instances where service accounts, which should typically authenticate using non-interactive methods like client credentials or managed identity flows, are instead signing in interactively via a browser. This behavior could indicate credential theft or an attacker using stolen credentials.
-
Data Source: It uses data from Azure Active Directory's SigninLogs.
-
Frequency: The query runs every 4 hours and looks at sign-in logs from the past 4 hours.
-
Network Allowlist: The query excludes sign-ins from trusted IP addresses or ranges specified in a "Network Allowlist" watchlist.
-
Service Account Identification: It looks for user principal names (UPNs) that contain keywords typically associated with service accounts, such as "svc", "app", "bot", etc.
-
Conditions: The query filters for successful sign-ins (ResultType "0") that are interactive (IsInteractive is true) and performed using a browser (ClientAppUsed is "Browser").
-
Output: It projects relevant details such as the time of the sign-in, user principal name, IP address, location, application name, risk level during sign-in, conditional access status, and user agent.
-
Alerting: If any such sign-ins are detected, an alert is generated with a high severity level. The alert includes details like the service account name and IP address used for the sign-in, suggesting possible credential theft.
-
Incident Management: The query is configured to create incidents for detected events, with grouping enabled based on account and IP to manage related alerts efficiently.
Overall, this query is a security measure to monitor and alert on potentially unauthorized or risky use of service accounts in an organization's Azure environment.
Details

David Alonso
Released: April 20, 2026
Tables
Keywords
Operators