Rules/APP-006.risky-delegated-grants.psd1
|
@{ Id = 'APP-006' Title = 'No risky delegated consent grants' Area = 'ConsentGrants' Severity = 'Medium' References = @( 'https://learn.microsoft.com/defender-cloud-apps/investigate-risky-oauth' ) Rationale = 'Delegated grants with write access to mail or files plus offline_access are the classic footprint of illicit consent-grant attacks - durable API access in user context, invisible to password resets.' Remediation = 'Review the flagged grants (who consented, is the app known?) and revoke unexpected ones; restrict future user consent (see ID-005).' Test = { param($Snapshot) $riskyScopes = @('Mail.ReadWrite', 'Mail.Send', 'MailboxSettings.ReadWrite', 'Files.ReadWrite.All', 'Sites.ReadWrite.All', 'Directory.ReadWrite.All', 'Contacts.ReadWrite', 'Notes.ReadWrite.All') $hits = [System.Collections.Generic.List[object]]::new() foreach ($grant in @($Snapshot.ConsentGrants.delegatedGrants)) { $scopeTokens = @(([string]$grant.scope) -split '\s+' | Where-Object { $_ }) $matched = @($scopeTokens | Where-Object { $riskyScopes -contains $_ }) if ($matched.Count -gt 0) { $clientLabel = $(if ($grant.PSObject.Properties['_tlClientName'] -and $grant._tlClientName) { $grant._tlClientName } else { $grant.clientId }) $hits.Add(("{0}: {1} ({2})" -f $clientLabel, ($matched -join ', '), $grant.consentType)) } } if ($hits.Count -gt 0) { New-TLRuleResult -Status Fail -Evidence @($hits | Select-Object -First 15) } else { New-TLRuleResult -Status Pass -Evidence ("No risky delegated scopes across {0} consent grants." -f @($Snapshot.ConsentGrants.delegatedGrants).Count) } } } |