Tenant has a Conditional Access policy that requires a managed device for MFA registration for all users
Microsoft Entra Conditional Access evaluates whether MFA registration is restricted to organization-managed devices. It looks for policies that target the security info registration action for all users and require a managed (compliant or hybrid-joined) device when registering authentication methods.
Risk
Allowing MFA enrollment from unmanaged or compromised devices enables attackers with stolen passwords to add their own factors, causing account takeover and potential lockout of the legitimate user.
This jeopardizes confidentiality (data access), integrity (unauthorized changes), and availability (user access disruption).
Run this check with Prowler
Run in Prowler Cloudprowler m365 --checks entra_managed_device_required_for_mfa_registrationRecommendation
Enforce MFA registration only from managed devices using Conditional Access. Apply the policy broadly, with minimal exclusions for break-glass accounts.
Align with Zero Trust and least privilege by requiring devices be compliant or hybrid-joined, monitoring enrollment activity, and regularly reviewing policies to prevent bypass and abuse.
Remediation
CLI
New-MgIdentityConditionalAccessPolicy -BodyParameter @{displayName="<example_resource_name>";state="enabled";conditions=@{users=@{includeUsers=@("All")};applications=@{includeUserActions=@("urn:user:registersecurityinfo")}};grantControls=@{operator="OR";builtInControls=@("mfa","domainJoinedDevice")}}Terraform
resource "azuread_conditional_access_policy" "<example_resource_name>" {
display_name = "<example_resource_name>"
state = "enabled" # Critical: policy must be enforced (not report-only)
conditions {
users {
include_users = ["All"] # Critical: applies to all users
}
applications {
include_user_actions = ["urn:user:registersecurityinfo"] # Critical: targets security info (MFA) registration
}
}
grant_controls {
operator = "OR" # Critical: required by the check logic
built_in_controls = ["mfa", "domainJoinedDevice"] # Critical: require MFA or hybrid joined device
}
}Other
Check Code
from prowler.lib.check.models import Check, CheckReportM365
from prowler.providers.m365.services.entra.entra_client import entra_client
from prowler.providers.m365.services.entra.entra_service import (
ConditionalAccessGrantControl,
ConditionalAccessPolicyState,
GrantControlOperator,
UserAction,
)
class entra_managed_device_required_for_mfa_registration(Check):
"""Check if Conditional Access policies enforce MFA registration on a managed device.
This check ensures that Conditional Access policies are in place to enforce MFA registration on a managed device.
"""
def execute(self) -> list[CheckReportM365]:
"""Execute the check to ensure that Conditional Access policies enforce MFA registration on a managed device.
Returns:
list[CheckReportM365]: A list containing the results of the check.
"""
findings = []
report = CheckReportM365(
metadata=self.metadata(),
resource={},
resource_name="Conditional Access Policies",
resource_id="conditionalAccessPolicies",
)
report.status = "FAIL"
report.status_extended = "No Conditional Access Policy requires a managed device for MFA registration."
for policy in entra_client.conditional_access_policies.values():
if policy.state == ConditionalAccessPolicyState.DISABLED:
continue
if "All" not in policy.conditions.user_conditions.included_users:
continue
if (
UserAction.REGISTER_SECURITY_INFO
not in policy.conditions.application_conditions.included_user_actions
):
continue
if (
ConditionalAccessGrantControl.DOMAIN_JOINED_DEVICE
not in policy.grant_controls.built_in_controls
or ConditionalAccessGrantControl.MFA
not in policy.grant_controls.built_in_controls
):
continue
if policy.grant_controls.operator == GrantControlOperator.OR:
report = CheckReportM365(
metadata=self.metadata(),
resource=policy,
resource_name=policy.display_name,
resource_id=policy.id,
)
if policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING:
report.status = "FAIL"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' reports the requirement of a managed device for MFA registration but does not enforce it."
else:
report.status = "PASS"
report.status_extended = f"Conditional Access Policy '{policy.display_name}' does require a managed device for MFA registration."
break
findings.append(report)
return findings