azure-appsvc-execute-as-via-attach-mi

Attach a privileged user-assigned MI to a site the attacker can already run code on, then execute as that MI. This is an existing-site chain (CanExecuteAs), NOT a create-new-workload chain.

derived azure emits CanExecuteAs

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} CanAttachIdentity {'site': None} {'principal': None} CanModifyCode {'site': None} {'site': None} ExecutesAs {'userMI': None}

where

node_type(?site) == ApplicationPlatform ?userMI is the user-assigned MI attached via the CanAttachIdentity edge and now bound to ?site (ExecutesAs) ?userMI.privilege_level >= ?principal.privilege_level # escalation only

optional

Present → upgrade the emitted state; absent → downgrade (not a hard requirement).

{'principal': None} CanStart {'site': None}

emit

source typeIdentity
target typeIdentity
source<principal>
target<user-assigned managed identity>
permissionsMicrosoft.ManagedIdentity/userAssignedIdentities/assign/action Microsoft.Web/sites/write Microsoft.Web/sites/publish/action
conditionsservice_state role_compatibility
state logicif ?site running: ACTIVE elif matched(optional[0]): ACTIVE # attacker can start/restart it else: CONDITIONAL(service_state)

Narrative

{principal.name} can attach user-assigned MI {userMI.name} to a site it can deploy code to, then run that code and mint {userMI.name}'s token from the App Service MSI endpoint, executing as {userMI.name}.

Raw rule rules/derived/azure/appservice.yaml

id: azure-appsvc-execute-as-via-attach-mi
emits: CanExecuteAs
description: Attach a privileged user-assigned MI to a site the attacker can already run code on, then
  execute as that MI. This is an existing-site chain (CanExecuteAs), NOT a create-new-workload chain.
match:
- - principal: null
  - CanAttachIdentity
  - site: null
- - principal: null
  - CanModifyCode
  - site: null
- - site: null
  - ExecutesAs
  - userMI: null
where:
- node_type(?site) == ApplicationPlatform
- ?userMI is the user-assigned MI attached via the CanAttachIdentity edge and now bound to ?site (ExecutesAs)
- '?userMI.privilege_level >= ?principal.privilege_level   # escalation only'
optional:
- - principal: null
  - CanStart
  - site: null
emit:
  source_type: Identity
  target_type: Identity
  source: <principal>
  target: <user-assigned managed identity>
  state_logic: 'if ?site running: ACTIVE

    elif matched(optional[0]): ACTIVE   # attacker can start/restart it

    else: CONDITIONAL(service_state)

    '
  permissions:
  - Microsoft.ManagedIdentity/userAssignedIdentities/assign/action
  - Microsoft.Web/sites/write
  - Microsoft.Web/sites/publish/action
  conditions:
  - service_state
  - role_compatibility
  derived_from:
  - <CanAttachIdentity edge_id>
  - <CanModifyCode edge_id>
  - <ExecutesAs edge_id>
  false_positive_note: Requires the attach chain (assign/action + sites/write) AND a code-exec primitive
    on that site AND the site to be running (or attacker CanStart it) so the deployed code runs and reaches
    the MSI endpoint. Escalation only if the attached MI out-privileges the caller. On a stopped app without
    CanStart -> CONDITIONAL(service_state).
  narrative: '{principal.name} can attach user-assigned MI {userMI.name} to a site it can deploy code
    to, then run that code and mint {userMI.name}''s token from the App Service MSI endpoint, executing
    as {userMI.name}.'
move · open · esc close