azure-msgraph-app-ownership
A service principal holding Application.ReadWrite.All can add itself as the owner of any app registration, granting it permanent owner-level control (credential addition, configuration change) independent of the original permission grant.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?sp) in [
MachineIdentity, ApplicationIdentity]
?approle is Application.ReadWrite.All (id: 1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9) on microsoft.graph SP
emit
| source type | Identity |
|---|---|
| target type | * |
| source | ?sp |
| target | <any ApplicationIdentity in the tenant> |
| permissions | Application.ReadWrite.All |
| conditions | iam_permission service_state |
| state logic | ACTIVE when the appRoleAssignment for Application.ReadWrite.All is granted and the SP credential is valid. CONDITIONAL(service_state) if SP credential is expired. Inherits weakest from the HasRole input. Not blocked by ARM RBAC deny assignments (Graph authorization is Entra-only). Elevated-privilege apps (Global Admin app registrations) may require additional authorization in future Entra hardening — flag CONDITIONAL in tenants with Entra Privileged Access hardening applied. |
Narrative
{sp.name} holds Application.ReadWrite.All and can add itself as owner of any app registration via POST /applications/{id}/owners/$ref, gaining permanent owner-level control over that app's credentials and configuration regardless of subsequent permission changes.
Raw rule rules/derived/azure/msgraph.yaml
id: azure-msgraph-app-ownership
emits: CanTakeOwnership
description: A service principal holding Application.ReadWrite.All can add itself as the owner of any
app registration, granting it permanent owner-level control (credential addition, configuration change)
independent of the original permission grant.
match:
- - sp: null
- HasRole
- approle: null
where:
- node_type(?sp) in [MachineIdentity, ApplicationIdentity]
- '?approle is Application.ReadWrite.All (id: 1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9) on microsoft.graph
SP'
emit:
source_type: Identity
target_type: '*'
source: ?sp
target: <any ApplicationIdentity in the tenant>
permissions:
- Application.ReadWrite.All
conditions:
- iam_permission
- service_state
state_logic: "ACTIVE when the appRoleAssignment for Application.ReadWrite.All is granted and the SP\
\ credential is valid. CONDITIONAL(service_state) if SP credential is expired. Inherits weakest from\
\ the HasRole input. Not blocked by ARM RBAC deny assignments (Graph authorization is Entra-only).\
\ Elevated-privilege apps (Global Admin app registrations) may require additional authorization in\
\ future Entra hardening \u2014 flag CONDITIONAL in tenants with Entra Privileged Access hardening\
\ applied."
confidence: '0.9'
derived_from:
- <HasRole edge_id (appRoleAssignment Application.ReadWrite.All on ?sp)>
- "azure/identity-escalation.yaml#azure-app-sp-ownership (object ownership path \u2014 parallel; this\
\ covers the app-permission path)"
false_positive_note: "CanTakeOwnership of every app is a significant blast-radius claim \u2014 the SP\
\ can add itself as owner of ANY app, including high-privilege first-party Microsoft apps (exchange,\
\ SharePoint). Practically, the first escalation step will target the highest-privilege SP in the\
\ tenant. This edge feeds the ownership -> CanCreateCredentialFor chain in identity-escalation.yaml\
\ (azure-app-sp-ownership). Do NOT emit if Application.ReadWrite.All is not present in appRoleAssignments.\
\ Dedupe with rule 2 (azure-msgraph-app-readwrite-cred) on (CanCreateCredentialFor, ?sp, ?target)\
\ \u2014 the two rules emit different edges (CanTakeOwnership here vs CanCreateCredentialFor in rule\
\ 2) so no dedup needed between rules, but both should reference the same appRoleAssignment."
narrative: '{sp.name} holds Application.ReadWrite.All and can add itself as owner of any app registration
via POST /applications/{id}/owners/$ref, gaining permanent owner-level control over that app''s credentials
and configuration regardless of subsequent permission changes.'