Back to Checks
m365

Tenant has a Conditional Access policy that requires a managed device for MFA registration for all users

entra_managed_device_required_for_mfa_registration
Service: entraSeverity: high
OfficialBuilt-inVerified
Categories:identity-accesse3
Resource Type:NotDefined

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 Cloud
Run
prowler m365 --checks entra_managed_device_required_for_mfa_registration

Recommendation

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

1Go to Microsoft Entra admin center > Protection > Conditional Access > Policies
2Click New policy
3Users: Include > All users
4Target resources: User actions > check Register security information
5Grant: Grant access > check Require multifactor authentication and Require Microsoft Entra hybrid joined device > select Require one of the selected controls
6Enable policy: On
7Click Create

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