Entra workload identity risk
Microsoft Entra ID Protection has an OPEN risk detection against a SERVICE PRINCIPAL — an application or automation identity, not a person.
What it detects
Microsoft Entra ID Protection has an OPEN risk detection against a SERVICE PRINCIPAL — an application or automation identity, not a person.
This is rated a step above the same detection on a human account (cloud.identity.entra_risk_detection, medium), and the reasons are properties of what a workload identity IS rather than of how badly it is behaving:
* **Nobody is watching it.** A service principal has no MFA prompt to decline and no user to notice a strange sign-in. The usual first signal of account takeover — the real owner saying "that wasn't me" — does not exist. * **Its permissions are usually broader.** App-only consent is commonly granted tenant-wide (Mail.Read, Files.Read.All, Directory.Read.All) because scoping it per-object is laborious. A compromised automation account frequently reaches more data than a compromised employee would. * **Its credentials are long-lived and portable.** Client secrets and certificates sit in CI configuration, deployment pipelines and source control. They do not expire on a schedule the way a session does, and they work from anywhere. * **Remediation is a deployment, not a password reset.** Rotating the credential means changing configuration and redeploying whatever uses it, so the window between detection and containment is measured in days.
Conditional access, sign-in risk policies and MFA — the controls an organisation relies on for people — mostly do not apply here. That is precisely why an attacker who can choose prefers to authenticate as an application.
MITRE ATT&CK mapping
False positives and triage
Workload identities generate a different kind of noise from people. An automation legitimately runs from a datacentre address, at unsociable hours, from more than one region, and its traffic pattern changes whenever the code that calls it is redeployed — so anomalousServicePrincipalActivity and suspiciousAPITraffic can both follow an ordinary release.
Correlate with change management before treating either as an incident: a deployment, a new integration, or a migration between regions explains most of them. What does NOT have a benign explanation is a credential detection (leakedCredentials) or a threat-intelligence match.
Start triage from the app registration rather than the sign-in: what API permissions does it hold, who consented to them, when was its credential last rotated, and does any human still own it. An orphaned automation nobody maintains is both the likeliest to be compromised and the least likely to be missed if disabled.
riskLevel: hidden here means the tenant lacks the licence to see the level (workload identity risk requires Workload Identities Premium). Treat it as "level unknown", never as "level low".
Note this rule and cloud.identity.entra_risk_detection will both fire on the same record. That is deliberate: the medium rule is a backstop that must stay unconditional, so it is not narrowed to exclude workload identities.
The rule
Declarative YAML read by the detection engine — data, never executed. Confidence 80%. Source: rules/cloud/entra_workload_identity_risk.yaml, licensed under the Apache License 2.0.
id: cloud.identity.entra_workload_identity_risk
version: 1.0.0
status: stable
severity: high
confidence: 0.8
platforms: [application]
mitre_techniques: [T1078.004, T1550.001]
description: |
Microsoft Entra ID Protection has an OPEN risk detection against a SERVICE
PRINCIPAL — an application or automation identity, not a person.
This is rated a step above the same detection on a human account
(`cloud.identity.entra_risk_detection`, medium), and the reasons are properties
of what a workload identity IS rather than of how badly it is behaving:
* **Nobody is watching it.** A service principal has no MFA prompt to decline
and no user to notice a strange sign-in. The usual first signal of account
takeover — the real owner saying "that wasn't me" — does not exist.
* **Its permissions are usually broader.** App-only consent is commonly
granted tenant-wide (`Mail.Read`, `Files.Read.All`, `Directory.Read.All`)
because scoping it per-object is laborious. A compromised automation account
frequently reaches more data than a compromised employee would.
* **Its credentials are long-lived and portable.** Client secrets and
certificates sit in CI configuration, deployment pipelines and source
control. They do not expire on a schedule the way a session does, and they
work from anywhere.
* **Remediation is a deployment, not a password reset.** Rotating the
credential means changing configuration and redeploying whatever uses it,
so the window between detection and containment is measured in days.
Conditional access, sign-in risk policies and MFA — the controls an
organisation relies on for people — mostly do not apply here. That is precisely
why an attacker who can choose prefers to authenticate as an application.
match:
provider: AzureAD
event_action: risk_detection
# Set by the normalizer from the record's own shape (servicePrincipalId /
# servicePrincipalDisplayName / appId), not inferred by the rule.
ext:azuread.identity_type: service_principal
ext:azuread.risk_state_any:
- atRisk
correlation_keys: [user_name, source_ip]
false_positive_guidance: |
Workload identities generate a different kind of noise from people. An
automation legitimately runs from a datacentre address, at unsociable hours,
from more than one region, and its traffic pattern changes whenever the code
that calls it is redeployed — so `anomalousServicePrincipalActivity` and
`suspiciousAPITraffic` can both follow an ordinary release.
Correlate with change management before treating either as an incident: a
deployment, a new integration, or a migration between regions explains most of
them. What does NOT have a benign explanation is a credential detection
(`leakedCredentials`) or a threat-intelligence match.
Start triage from the app registration rather than the sign-in: what API
permissions does it hold, who consented to them, when was its credential last
rotated, and does any human still own it. An orphaned automation nobody
maintains is both the likeliest to be compromised and the least likely to be
missed if disabled.
`riskLevel: hidden` here means the tenant lacks the licence to see the level
(workload identity risk requires Workload Identities Premium). Treat it as
"level unknown", never as "level low".
Note this rule and `cloud.identity.entra_risk_detection` will both fire on the
same record. That is deliberate: the medium rule is a backstop that must stay
unconditional, so it is not narrowed to exclude workload identities.
Related detections
Run this rule on your own logs — offline
KIROSEC runs this rule and the rest of the library over Windows, Linux, macOS and cloud audit logs on the analyst's own machine. Every alert links to the events that raised it, and nothing leaves the device.
