Back to Checks
m365

At least one Conditional Access policy enforces Identity Protection user risk for high-risk users

entra_identity_protection_user_risk_enabled
Service: entraSeverity: high
OfficialBuilt-inVerified
Categories:identity-accesse5
Resource Type:NotDefined

Microsoft Entra Conditional Access has a user risk-based policy that targets All users and All applications, evaluates High user risk, and actively enforces controls requiring both multifactor authentication and a secure password change with an AND condition.

Risk

Without an active High user-risk policy that forces MFA and secure password reset, compromised identities can persist, enabling data exfiltration, tampering, and privilege escalation. Report-only mode or narrow scope leaves gaps, undermining confidentiality and integrity across resources.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler m365 --checks entra_identity_protection_user_risk_enabled

Recommendation

Adopt least privilege by enabling an active user-risk policy that:

  • covers All users and apps (exclude only break-glass)
  • triggers on High user risk
  • requires MFA and a secure password change together
  • reauthenticates risky sessions

Pair with sign-in risk policies, ensure MFA registration, and review risky-user reports to validate effectiveness.

Remediation

Terraform

resource "azuread_conditional_access_policy" "<example_resource_name>" {
  display_name = "<example_resource_name>"
  state        = "enabled"

  conditions {
    client_app_types = ["all"]
    users {
      include_users = ["All"] # Critical: targets all users
    }
    applications {
      included_applications = ["All"] # Critical: applies to all cloud apps
    }
    user_risk_levels = ["high"] # Critical: enforces on high user risk
  }

  grant_controls {
    operator          = "AND" # Critical: require all selected controls
    built_in_controls = ["mfa", "passwordChange"] # Critical: require MFA and password change
  }
}

Other

1Sign in to the Microsoft Entra admin center and go to Protection > Conditional Access > Policies
2Click New policy
3Users or workload identities: select All users
4Target resources (Cloud apps): select All cloud apps
5Conditions > User risk: set Configure to Yes and select High
6Access controls > Grant: select Grant access, then check Require multifactor authentication and Require password change; set Require all selected controls
7Enable policy: On, then click 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,
    RiskLevel,
)


class entra_identity_protection_user_risk_enabled(Check):
    """Check if at least one Conditional Access policy is an Identity Protection user risk policy.

    This check ensures that at least one Conditional Access policy is an Identity Protection user risk policy.
    """

    def execute(self) -> list[CheckReportM365]:
        """Execute the check to ensure that at least one Conditional Access policy is an Identity Protection user risk policy.

        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 is a user risk based Identity Protection Policy."

        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 (
                "All"
                not in policy.conditions.application_conditions.included_applications
            ):
                continue

            if (
                ConditionalAccessGrantControl.PASSWORD_CHANGE
                not in policy.grant_controls.built_in_controls
                or ConditionalAccessGrantControl.MFA
                not in policy.grant_controls.built_in_controls
                or policy.grant_controls.operator != GrantControlOperator.AND
            ):
                continue

            if policy.conditions.user_risk_levels:
                report = CheckReportM365(
                    metadata=self.metadata(),
                    resource=policy,
                    resource_name=policy.display_name,
                    resource_id=policy.id,
                )
                if RiskLevel.HIGH not in policy.conditions.user_risk_levels:
                    report.status = "FAIL"
                    report.status_extended = f"Conditional Access Policy '{policy.display_name}' is a user risk based Identity Protection Policy but does not protect against high risk potential account compromises."
                elif policy.state == ConditionalAccessPolicyState.ENABLED_FOR_REPORTING:
                    report.status = "FAIL"
                    report.status_extended = f"Conditional Access Policy '{policy.display_name}' is a user risk based Identity Protection Policy and reports high risk potential account compromises, but does not protect against them."
                else:
                    report.status = "PASS"
                    report.status_extended = f"Conditional Access Policy '{policy.display_name}' is a user risk based Identity Protection Policy and does protect against high risk potential account compromises."
                    break

        findings.append(report)

        return findings