Checks/EXO/MET-EXO013-SpoofIntelligenceAllowList.ps1
|
[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', 'METCheckInfo', Justification = 'Check metadata. Read from the AST by Get-METCheck and never executed.')] param() $METCheckInfo = @{ Name = 'Spoof Intelligence Allow-List' Severity = 'High' Description = 'Reviews standing spoof-intelligence allow entries from Get-TenantAllowBlockListSpoofItems, distinguishing Internal from External spoof type.' RequiresModule = @('ExchangeOnlineManagement') } try { $allowEntries = @(Get-TenantAllowBlockListSpoofItems -Action Allow -ErrorAction Stop) } catch { New-METCheckResult -CheckId 'MET-EXO013' -Category EXO -Name 'Spoof Intelligence Allow-List' ` -Result Fail -Severity High -AffectedObject 'Spoof Intelligence Allow List' ` -Finding 'Unable to retrieve spoof intelligence allow entries' ` -Recommendation 'Ensure the account has Security Reader or higher permissions.' ` -ReferenceUrl 'https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/get-tenantallowblocklistspoofitems' ` -ErrorMessage $_.ToString() return } if ($allowEntries.Count -eq 0) { New-METCheckResult -CheckId 'MET-EXO013' -Category EXO -Name 'Spoof Intelligence Allow-List' ` -Result Info -Severity Low -AffectedObject 'Spoof Intelligence Allow List' ` -Finding 'No spoof intelligence allow entries found - no standing exceptions to anti-spoofing protection' ` -ReferenceUrl 'https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/get-tenantallowblocklistspoofitems' return } $count = $allowEntries.Count $unclassified = @($allowEntries | Where-Object { -not $_.PSObject.Properties['SpoofType'] -or $null -eq $_.SpoofType }) $externalCount = @($allowEntries | Where-Object { $_.PSObject.Properties['SpoofType'] -and $_.SpoofType -eq 'External' }).Count $samples = $allowEntries | Select-Object -First 10 | ForEach-Object { $spoofTypeText = if (-not $_.PSObject.Properties['SpoofType'] -or $null -eq $_.SpoofType) { 'spoof type not returned' } else { $_.SpoofType } "$($_.SpoofedUser) via $($_.SendingInfrastructure) ($spoofTypeText)" } $findingParts = [System.Collections.Generic.List[string]]::new() if ($unclassified.Count -gt 0) { $findingParts.Add("$count spoof intelligence allow entry(ies) found ($externalCount External, $($unclassified.Count) of $count entries did not report a spoof type)") } else { $findingParts.Add("$count spoof intelligence allow entry(ies) found ($externalCount External)") } $findingParts.Add(($samples -join '; ')) if ($count -gt 10) { $findingParts.Add("...and $($count - 10) more") } $errorMessage = if ($unclassified.Count -gt 0) { "$($unclassified.Count) of $count entries returned by Get-TenantAllowBlockListSpoofItems did not include a SpoofType value, so the Internal/External split above is a lower bound for External." } else { $null } New-METCheckResult -CheckId 'MET-EXO013' -Category EXO -Name 'Spoof Intelligence Allow-List' ` -Result Warning -Severity High -AffectedObject "Spoof Intelligence Allow List ($count entries)" ` -Finding ($findingParts -join '; ') ` -Recommendation 'Review each allowed spoof pair. These are often created automatically when spoof intelligence learns a legitimate sender pattern, or manually during incident response, and are meant to be periodically reviewed - not permanent. Remove entries for senders/infrastructure no longer in use. External spoof types are higher risk than Internal since they permit an outside domain to impersonate a sender address. Run: Get-TenantAllowBlockListSpoofItems -Action Allow | Remove-TenantAllowBlockListSpoofItems to clean up stale entries.' ` -ReferenceUrl 'https://learn.microsoft.com/en-us/powershell/module/exchangepowershell/get-tenantallowblocklistspoofitems' ` -ErrorMessage $errorMessage |