Entra workload credential leaked
Microsoft found a SERVICE PRINCIPAL's credential published somewhere public and the detection is still open.
What it detects
Microsoft found a SERVICE PRINCIPAL's credential published somewhere public and the detection is still open.
leakedCredentials is not a behavioural score. Microsoft matches credential material found in public source repositories, paste sites and dark-web dumps against the tenant's own identities. When it fires, a secret that authenticates an application identity is, or was, publicly readable.
This is separated from cloud.identity.entra_workload_identity_risk (high) and raised to critical because of what the credential is:
* A client secret or certificate is a **bearer** credential. Anyone holding it is the application — no second factor, no device, no user interaction, from any address on the internet. * It carries the app's **app-only permissions**, which are commonly tenant-wide. There is no per-user scope limiting the blast radius. * It stays valid until somebody rotates it. Revoking sessions does nothing; disabling a user does nothing. The credential itself has to be removed. * Leaks are usually **historical by the time they are detected** — the secret was committed, the commit was pushed, and the repository may have been public for months. Assume use, then look for it.
The immediate action is rotation, not investigation: remove the credential from the app registration first, then work out what it did while it was valid.
MITRE ATT&CK mapping
False positives and triage
Very few, and none of them mean "ignore it". Microsoft matches real credential material, so a match is evidence the secret was exposed even if the exposure was brief or the repository has since been made private — the secret is still burned and still has to be rotated.
The realistic false alarm is a STALE detection: a credential leaked, detected, and rotated some time ago, whose record is re-imported with a historical log pull and read as current. Check the detection's timestamp against the case window, and check whether the named credential (keyIds in the preserved payload) still exists on the app registration.
A test or sample credential committed deliberately to a demo repository will also match. That is a real leak of a real credential; the correct response is still rotation, and the lesson is that the demo should not have used a tenant identity.
Do NOT treat "the app looks idle" as reassurance. App-only tokens leave no interactive sign-in trail, so absence of obvious activity is weak evidence. Check the app's own sign-in logs and the Graph activity for the app id.
The rule
Declarative YAML read by the detection engine — data, never executed. Confidence 90%. Source: rules/cloud/entra_workload_credential_leaked.yaml, licensed under the Apache License 2.0.
id: cloud.identity.entra_workload_credential_leaked
version: 1.0.0
status: stable
severity: critical
confidence: 0.9
platforms: [application]
mitre_techniques: [T1552, T1552.001, T1078.004]
description: |
Microsoft found a SERVICE PRINCIPAL's credential published somewhere public and
the detection is still open.
`leakedCredentials` is not a behavioural score. Microsoft matches credential
material found in public source repositories, paste sites and dark-web dumps
against the tenant's own identities. When it fires, a secret that authenticates
an application identity is, or was, publicly readable.
This is separated from `cloud.identity.entra_workload_identity_risk` (high) and
raised to critical because of what the credential is:
* A client secret or certificate is a **bearer** credential. Anyone holding it
is the application — no second factor, no device, no user interaction, from
any address on the internet.
* It carries the app's **app-only permissions**, which are commonly
tenant-wide. There is no per-user scope limiting the blast radius.
* It stays valid until somebody rotates it. Revoking sessions does nothing;
disabling a user does nothing. The credential itself has to be removed.
* Leaks are usually **historical by the time they are detected** — the secret
was committed, the commit was pushed, and the repository may have been
public for months. Assume use, then look for it.
The immediate action is rotation, not investigation: remove the credential from
the app registration first, then work out what it did while it was valid.
match:
provider: AzureAD
event_action: risk_detection
ext:azuread.identity_type: service_principal
ext:azuread.risk_event_type: leakedCredentials
ext:azuread.risk_state_any:
- atRisk
correlation_keys: [user_name, source_ip]
false_positive_guidance: |
Very few, and none of them mean "ignore it". Microsoft matches real credential
material, so a match is evidence the secret was exposed even if the exposure was
brief or the repository has since been made private — the secret is still burned
and still has to be rotated.
The realistic false alarm is a STALE detection: a credential leaked, detected,
and rotated some time ago, whose record is re-imported with a historical log
pull and read as current. Check the detection's timestamp against the case
window, and check whether the named credential (`keyIds` in the preserved
payload) still exists on the app registration.
A test or sample credential committed deliberately to a demo repository will
also match. That is a real leak of a real credential; the correct response is
still rotation, and the lesson is that the demo should not have used a tenant
identity.
Do NOT treat "the app looks idle" as reassurance. App-only tokens leave no
interactive sign-in trail, so absence of obvious activity is weak evidence.
Check the app's own sign-in logs and the Graph activity for the app id.
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.
