azure-msgraph-user-password-reset
A service principal holding User.ReadWrite.All (or Directory.ReadWrite.All) can reset any non-protected Entra user's password via PATCH /users/{id} with a new passwordProfile, taking over that user's account and inheriting their RBAC and group memberships.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?sp) in [
MachineIdentity, ApplicationIdentity]
?approle is one of: User.ReadWrite.All (id: 741f803b-c850-494e-b5df-cde7c675a1ca) OR Directory.ReadWrite.All (id: 19dbc75e-c2e2-444c-a770-ec69d8559fc7) on microsoft.graph SP
for all HumanIdentity nodes (?user) in the tenant where ?user is NOT a protected administrator in Entra (Global Administrator, Privileged Role Administrator, Password Administrator, User Administrator, Authentication Administrator, Helpdesk Administrator — cross-check against /roleManagement/directory/roleAssignments)
emit
| source type | Identity |
|---|---|
| target type | HumanIdentity |
| source | ?sp |
| target | ?user |
| permissions | User.ReadWrite.All Directory.ReadWrite.All |
| conditions | iam_permission service_state |
| state logic | ACTIVE when the appRoleAssignment is granted, SP credential is valid, and the target user is confirmed NOT a protected administrator. BLOCKED when the target user holds Global Administrator, Privileged Role Administrator, or any other role that Entra restricts from credential reset by lower-tier actors (Entra enforces this at API call time — the PATCH returns 403). CONDITIONAL(service_state) if the SP credential is expired. If the target user's role membership cannot be confirmed (collection gap), emit as CONDITIONAL(role_compatibility) and flag for analyst review. Conditional Access policies requiring MFA to set passwordProfile do not block an SP calling as itself (app-only context); they apply to interactive sessions. |
Narrative
{sp.name} holds User.ReadWrite.All and can reset the password of {user.name} via PATCH /users/{id} (passwordProfile), taking over their account and inheriting all RBAC role assignments and group memberships they hold - subject to Entra's restriction blocking resets of protected administrator accounts.
Raw rule rules/derived/azure/msgraph.yaml
id: azure-msgraph-user-password-reset
emits: CanResetCredential
description: A service principal holding User.ReadWrite.All (or Directory.ReadWrite.All) can reset any
non-protected Entra user's password via PATCH /users/{id} with a new passwordProfile, taking over that
user's account and inheriting their RBAC and group memberships.
match:
- - sp: null
- HasRole
- approle: null
where:
- node_type(?sp) in [MachineIdentity, ApplicationIdentity]
- '?approle is one of: User.ReadWrite.All (id: 741f803b-c850-494e-b5df-cde7c675a1ca) OR Directory.ReadWrite.All
(id: 19dbc75e-c2e2-444c-a770-ec69d8559fc7) on microsoft.graph SP'
- "for all HumanIdentity nodes (?user) in the tenant where ?user is NOT a protected administrator in Entra\
\ (Global Administrator, Privileged Role Administrator, Password Administrator, User Administrator,\
\ Authentication Administrator, Helpdesk Administrator \u2014 cross-check against /roleManagement/directory/roleAssignments)"
emit:
source_type: Identity
target_type: HumanIdentity
source: ?sp
target: ?user
permissions:
- User.ReadWrite.All
- Directory.ReadWrite.All
conditions:
- iam_permission
- service_state
state_logic: "ACTIVE when the appRoleAssignment is granted, SP credential is valid, and the target user\
\ is confirmed NOT a protected administrator. BLOCKED when the target user holds Global Administrator,\
\ Privileged Role Administrator, or any other role that Entra restricts from credential reset by lower-tier\
\ actors (Entra enforces this at API call time \u2014 the PATCH returns 403). CONDITIONAL(service_state)\
\ if the SP credential is expired. If the target user's role membership cannot be confirmed (collection\
\ gap), emit as CONDITIONAL(role_compatibility) and flag for analyst review. Conditional Access policies\
\ requiring MFA to set passwordProfile do not block an SP calling as itself (app-only context); they\
\ apply to interactive sessions."
confidence: '0.9'
derived_from:
- <HasRole edge_id (appRoleAssignment User.ReadWrite.All or Directory.ReadWrite.All on ?sp)>
- "azure/identity-escalation.yaml#azure-reset-password (directory-role path covering Authentication/User\
\ Administrator \u2014 parallel; this covers the app-permission path)"
false_positive_note: "Entra's restricted-admin protection prevents password reset for users holding\
\ privileged directory roles \u2014 the API enforces this, not just convention. Always check the target\
\ user's role assignments; if the user holds ANY admin directory role, emit BLOCKED rather than ACTIVE\
\ (unless the collector confirms the role set is empty). User.ReadWrite.All does NOT permit resetting\
\ MFA methods (that requires Authentication.ReadWrite \u2014 not modeled here). Directory.ReadWrite.All\
\ may not cover passwordProfile update in all Entra configurations \u2014 prefer User.ReadWrite.All\
\ appRoleId match for highest confidence. Self-service password reset (SSPR) does not interact with\
\ this edge (this is an app-only API call, not user-initiated). The rule matches all HumanIdentity\
\ nodes (regardless of prior role assignment data), filtering out protected admins at the where clause;\
\ non-admin users without any direct directory role are valid targets and must not be silently excluded\
\ by match-time role constraints."
narrative: "{sp.name} holds User.ReadWrite.All and can reset the password of {user.name} via PATCH /users/{id}\
\ (passwordProfile), taking over their account and inheriting all RBAC role assignments and group\
\ memberships they hold \u2014 subject to Entra's restriction blocking resets of protected administrator\
\ accounts."