Rules/CA-007.trusted-locations-scoped.psd1

@{
    Id          = 'CA-007'
    Title       = 'Trusted named locations are tightly scoped'
    Area        = 'NamedLocations'
    Severity    = 'High'
    References  = @(
        'https://learn.microsoft.com/entra/identity/conditional-access/concept-assignment-network'
    )
    Rationale   = 'A trusted location covering huge address space (up to 0.0.0.0/0) silently disables every "exclude trusted locations" condition - MFA skips and risk policies stop applying almost everywhere.'
    Remediation = 'Restrict trusted named locations to the actual corporate egress ranges; remove catch-all ranges.'
    Test        = {
        param($Snapshot)
        $broad = [System.Collections.Generic.List[string]]::new()
        foreach ($location in @($Snapshot.NamedLocations)) {
            $type = ([string]$location.'@odata.type') -replace '^#microsoft\.graph\.', ''
            if ($type -ne 'ipNamedLocation' -or -not $location.isTrusted) { continue }
            foreach ($range in @($location.ipRanges)) {
                $cidr = [string]$range.cidrAddress
                if ($cidr -match '/(\d+)$') {
                    $prefix = [int]$Matches[1]
                    $isV6 = $cidr -match ':'
                    $threshold = $(if ($isV6) { 16 } else { 8 })
                    if ($prefix -lt $threshold) {
                        $broad.Add(("{0}: {1}" -f $location.displayName, $cidr))
                    }
                }
            }
        }
        if ($broad.Count -gt 0) {
            New-TLRuleResult -Status Fail -Evidence @($broad)
        }
        else {
            $trustedCount = @($Snapshot.NamedLocations | Where-Object { $_.isTrusted }).Count
            New-TLRuleResult -Status Pass -Evidence ("{0} trusted location(s), all tightly scoped." -f $trustedCount)
        }
    }
}