azure-msgraph-fedcred-add

A service principal holding Application.ReadWrite.All or Directory.ReadWrite.All can modify the trust configuration of any app registration by adding a federated identity credential (OIDC trust), allowing an attacker-controlled external issuer to obtain tokens as that app without a static secret.

derived azure emits CanModifyTrust

match

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

{'sp': None} HasRole {'approle': None}

where

node_type(?sp) in [MachineIdentity, ApplicationIdentity] ?approle is one of: Application.ReadWrite.All (id: 1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9) OR Directory.ReadWrite.All (id: 19dbc75e-c2e2-444c-a770-ec69d8559fc7) on microsoft.graph SP for all ApplicationIdentity nodes (?target_app) in the tenant where ?sp != ?target_app

emit

source typeIdentity
target typeMachineIdentity
source?sp
target?target_app (service principal / app trust configuration)
permissionsApplication.ReadWrite.All Directory.ReadWrite.All
conditionsiam_permission service_state
state logicACTIVE when the appRoleAssignment is granted and SP credential is valid. CONDITIONAL(service_state) if SP credential expired. Downstream federation path (TrustsExternalIdentity -> ExternalIdentityMapsTo -> CanFederateAs) is governed by federation-chains.yaml federation-maps-to-identity and depends on the attacker controlling an OIDC issuer whose tokens satisfy the federated credential's issuer/subject/audience conditions; that downstream state is CONDITIONAL(trust_condition) until confirmed broad/unpinned.

Narrative

{sp.name} holds Application.ReadWrite.All and can modify the configuration of {target_app.name} by adding a federated identity credential via POST /applications/{id}/federatedIdentityCredentials, configuring it to trust an attacker-controlled OIDC issuer; an external identity matching that trust can then obtain tokens as {target_app.name} without any static secret.

Raw rule rules/derived/azure/msgraph.yaml

id: azure-msgraph-fedcred-add
emits: CanModifyTrust
description: A service principal holding Application.ReadWrite.All or Directory.ReadWrite.All can modify
  the trust configuration of any app registration by adding a federated identity credential (OIDC trust),
  allowing an attacker-controlled external issuer to obtain tokens as that app without a static secret.
match:
- - sp: null
  - HasRole
  - approle: null
where:
- node_type(?sp) in [MachineIdentity, ApplicationIdentity]
- '?approle is one of: Application.ReadWrite.All (id: 1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9) OR Directory.ReadWrite.All
  (id: 19dbc75e-c2e2-444c-a770-ec69d8559fc7) on microsoft.graph SP'
- for all ApplicationIdentity nodes (?target_app) in the tenant where ?sp != ?target_app
emit:
  source_type: Identity
  target_type: MachineIdentity
  source: ?sp
  target: ?target_app (service principal / app trust configuration)
  permissions:
  - Application.ReadWrite.All
  - Directory.ReadWrite.All
  conditions:
  - iam_permission
  - service_state
  state_logic: ACTIVE when the appRoleAssignment is granted and SP credential is valid. CONDITIONAL(service_state)
    if SP credential expired. Downstream federation path (TrustsExternalIdentity -> ExternalIdentityMapsTo
    -> CanFederateAs) is governed by federation-chains.yaml federation-maps-to-identity and depends on
    the attacker controlling an OIDC issuer whose tokens satisfy the federated credential's issuer/subject/audience
    conditions; that downstream state is CONDITIONAL(trust_condition) until confirmed broad/unpinned.
  confidence: '0.9'
  derived_from:
  - <HasRole edge_id (appRoleAssignment Application.ReadWrite.All or Directory.ReadWrite.All on ?sp)>
  - "azure/identity-escalation.yaml#azure-federated-credential-write (object-ownership/credential-update\
    \ path \u2014 parallel; this covers the app-permission path)"
  - federation-chains.yaml#federation-maps-to-identity (consumes the resulting TrustsExternalIdentity
    + ExternalIdentityMapsTo pair)
  false_positive_note: "Adding a federated credential requires: (a) SP credential is valid to call Graph;\
    \ (b) target app allows federatedIdentityCredentials (most do by default). The attack is a two-step:\
    \ add the fedcred (this edge = CanModifyPolicy on the app configuration), then use an attacker-controlled\
    \ external identity that satisfies the issuer/sub/aud criteria to obtain a token (federation-chains\
    \ handles the downstream). Do NOT model the downstream CanFederateAs here \u2014 let federation-chains\
    \ derive it. Do NOT emit for the SP's OWN app (self-modification does not escalate if the SP already\
    \ has Application.ReadWrite.All; it may still be a persistence mechanism \u2014 flag separately if\
    \ needed). Confidence reduced from rule 2 because the downstream federation step adds friction. This\
    \ rule emits CanModifyPolicy for every ApplicationIdentity in the tenant, creating significant fan-out;\
    \ queries should filter by target privilege score when seeking high-impact paths."
  narrative: '{sp.name} holds Application.ReadWrite.All and can modify the configuration of {target_app.name}
    by adding a federated identity credential via POST /applications/{id}/federatedIdentityCredentials,
    configuring it to trust an attacker-controlled OIDC issuer; an external identity matching that trust
    can then obtain tokens as {target_app.name} without any static secret.'
move · open · esc close