azure-msgraph-multitenant-app-consent

A multi-tenant application registration that has been granted admin consent by a foreign Entra tenant creates a cross-tenant trust allowing the app's SP in the foreign tenant to act under the consented permissions. If the app or its home-tenant SP is compromised, the attacker gains a foothold in the foreign tenant - a lateral-movement primitive.

derived azure emits CrossTenantTrust

match

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

{'app': None} LocatedIn {'home_tenant': None}

where

node_type(?app) == ApplicationIdentity ?app.signInAudience != 'AzureADMyOrg' # multi-tenant or personal-account ?foreign_sp is a service principal for ?app (same appId) in a foreign_tenant where ?foreign_sp.tenantId != ?home_tenant.id ?foreign_sp has received admin consent (evidenced by appRoleAssignment or oAuth2PermissionGrant in foreign_tenant)

emit

source typeApplicationIdentity
target typeExternalIdentity
source?app
target<foreign tenant or foreign tenant's external identity representing the consent>
conditionstrust_relationship
state logicACTIVE when the app has signInAudience=Multitenant or AzureADandPersonalMicrosoftAccount AND an appRoleAssignment or oAuth2PermissionGrant exists in the foreign tenant showing admin consent has been granted. BLOCKED if the app is restricted by the foreign tenant's tenant-level restrictions (e.g., "only allow specific app policy"). The foreign tenant's SP for this app then holds the consented permissions and can act as an attacker foothold there.

Narrative

{app.name} is a multi-tenant application that has been granted admin consent in a foreign Entra tenant. The app's service principal in the foreign tenant now holds the consented permissions and can act on behalf of the attacker if the home-tenant app or its credentials are compromised - enabling lateral movement into the foreign tenant.

Raw rule rules/derived/azure/msgraph.yaml

id: azure-msgraph-multitenant-app-consent
emits: CrossTenantTrust
description: "A multi-tenant application registration that has been granted admin consent by a foreign\
  \ Entra tenant creates a cross-tenant trust allowing the app's SP in the foreign tenant to act under\
  \ the consented permissions. If the app or its home-tenant SP is compromised, the attacker gains a foothold\
  \ in the foreign tenant \u2014 a lateral-movement primitive."
match:
- - app: null
  - LocatedIn
  - home_tenant: null
where:
- node_type(?app) == ApplicationIdentity
- '?app.signInAudience != ''AzureADMyOrg''  # multi-tenant or personal-account'
- ?foreign_sp is a service principal for ?app (same appId) in a foreign_tenant where ?foreign_sp.tenantId
  != ?home_tenant.id
- ?foreign_sp has received admin consent (evidenced by appRoleAssignment or oAuth2PermissionGrant in foreign_tenant)
emit:
  source_type: ApplicationIdentity
  target_type: ExternalIdentity
  source: ?app
  target: <foreign tenant or foreign tenant's external identity representing the consent>
  permissions: []
  conditions:
  - trust_relationship
  state_logic: ACTIVE when the app has signInAudience=Multitenant or AzureADandPersonalMicrosoftAccount
    AND an appRoleAssignment or oAuth2PermissionGrant exists in the foreign tenant showing admin consent
    has been granted. BLOCKED if the app is restricted by the foreign tenant's tenant-level restrictions
    (e.g., "only allow specific app policy"). The foreign tenant's SP for this app then holds the consented
    permissions and can act as an attacker foothold there.
  confidence: '0.95'
  derived_from:
  - <Application.signInAudience flag (multitenant setting)>
  - <appRoleAssignment or oAuth2PermissionGrant in foreign_tenant>
  - providers/azure/msgraph.md#section-10 (cross-boundary access via multi-tenant)
  false_positive_note: "Only multi-tenant and personal-account apps create cross-tenant trust; single-tenant\
    \ (AzureADMyOrg) apps cannot be consented to by foreign tenants. Always confirm the app's signInAudience\
    \ setting; if it is AzureADMyOrg, this edge does not apply. The presence of an appRoleAssignment in\
    \ the foreign tenant is the definitive evidence of admin consent. Do NOT emit if the foreign tenant's\
    \ admin has revoked consent (appRoleAssignment deleted or oAuth2PermissionGrant revoked) \u2014 model\
    \ as BLOCKED or deletion."
  narrative: "{app.name} is a multi-tenant application that has been granted admin consent in a foreign\
    \ Entra tenant. The app's service principal in the foreign tenant now holds the consented permissions\
    \ and can act on behalf of the attacker if the home-tenant app or its credentials are compromised\
    \ \u2014 enabling lateral movement into the foreign tenant."
move · open · esc close