Rules/MFA-003.admins-phishing-resistant.psd1

@{
    Id          = 'MFA-003'
    Title       = 'Administrators use phishing-resistant authentication methods'
    Area        = 'MfaRegistration'
    Severity    = 'High'
    References  = @(
        'https://learn.microsoft.com/entra/identity/authentication/concept-authentication-strengths'
    )
    Rationale   = 'Push/OTP MFA still falls to real-time phishing and fatigue attacks. For admin accounts the bar is passkeys, FIDO2 or Windows Hello for Business.'
    Remediation = 'Register a phishing-resistant method (passkey, FIDO2 key, Windows Hello for Business) for every admin and enforce it via an authentication strength in Conditional Access.'
    Test        = {
        param($Snapshot)
        # Exclude directory-sync service accounts - they never sign in interactively.
        $syncUpns = Get-TLSyncAccountUpn -Snapshot $Snapshot
        $admins = @($Snapshot.MfaRegistration.users | Where-Object { $_.isAdmin -and -not $syncUpns.Contains([string]$_.userPrincipalName) })
        if ($admins.Count -eq 0) {
            return New-TLRuleResult -Status Manual -Evidence 'No interactive admin entries in the registration report - review manually.'
        }
        $phishingResistantPattern = '(?i)(fido2|passKey|windowsHelloForBusiness|certificate)'
        $weakAdmins = @($admins | Where-Object {
                @($_.methodsRegistered | Where-Object { $_ -match $phishingResistantPattern }).Count -eq 0
            })
        if ($weakAdmins.Count -gt 0) {
            New-TLRuleResult -Status Fail -Evidence @($weakAdmins | Select-Object -First 10 | ForEach-Object {
                    "{0}: {1}" -f $_.userPrincipalName, $(if (@($_.methodsRegistered).Count -gt 0) { @($_.methodsRegistered) -join ', ' } else { 'no methods registered' })
                })
        }
        else {
            New-TLRuleResult -Status Pass -Evidence ("All {0} interactive admins have a phishing-resistant method registered." -f $admins.Count)
        }
    }
}