Query Details
id: c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f
name: "SigninLogs — Service Account Interactive Browser Sign-In"
version: 1.0.0
kind: Scheduled
description: |
Detects service accounts and non-human identities performing interactive browser-based sign-ins. Service accounts should only authenticate via client credentials or managed identity flows. Interactive sessions indicate credential theft or an attacker manually leveraging stolen service account creds. MITRE ATT&CK: T1078 (Valid Accounts), T1078.004 (Cloud Accounts).
severity: High
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
queryFrequency: PT4H
queryPeriod: PT4H
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- Persistence
relevantTechniques:
- T1078
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,
UserAgent
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserPrincipalName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
customDetails:
AppDisplayName: AppDisplayName
CAStatus: CAStatus
alertDetailsOverride:
alertDisplayNameFormat: "Service Account Interactive Login — {{UserPrincipalName}} from {{IPAddress}}"
alertDescriptionFormat: "Service account {{UserPrincipalName}} used a browser session from {{IPAddress}} — service accounts should never authenticate interactively. Possible credential theft."
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT4H
matchingMethod: AllEntities
groupByEntities:
- Account
- IP
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.

David Alonso
Released: April 20, 2026
Tables
Keywords
Operators