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.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
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> |
| 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. |
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."