Back to Checks
m365

Defender anti-malware policy has admin notifications enabled for internal users sending malware

defender_malware_policy_notifications_internal_users_malware_enabled
Service: defenderSeverity: medium
OfficialBuilt-inVerified
Categories:email-securitye3
Resource Type:NotDefined

Microsoft Defender for Office 365 anti-malware policies are checked for admin notifications on malware detected from internal senders, ensuring a valid notification address is defined (EnableInternalSenderAdminNotifications and InternalSenderAdminAddress).

Effective settings across default and custom policies are considered.

Risk

Without these notifications, malware sent from internal accounts can persist unnoticed, delaying response and containment. This undermines integrity of email, enables lateral movement and outbound propagation, and can cause domain reputation damage and blocklisting, affecting availability.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler m365 --checks defender_malware_policy_notifications_internal_users_malware_enabled

Recommendation

Enable and maintain admin alerts for internal-sender malware and route to a monitored mailbox or SOC list (EnableInternalSenderAdminNotifications and InternalSenderAdminAddress).

Ensure coverage via policy precedence, integrate with SIEM, and apply least privilege and defense in depth to limit impact.

Remediation

CLI

Set-MalwareFilterPolicy -Identity Default -EnableInternalSenderAdminNotifications $true -InternalSenderAdminAddress "<ADMIN_EMAIL>"

Other

1In the Microsoft Defender portal (security.microsoft.com), go to Email & collaboration > Policies & rules > Threat policies > Anti-malware
2Select the affected policy (e.g., Default) and click Edit policy
3Open Notifications
4Turn on "Notify an admin about undelivered messages from internal senders"
5Add at least one Administrator email address
6Save

Check Code

from typing import List

from prowler.lib.check.models import Check, CheckReportM365
from prowler.providers.m365.services.defender.defender_client import defender_client


class defender_malware_policy_notifications_internal_users_malware_enabled(Check):
    """
    Check if notifications for internal users sending malware are enabled in the Defender anti-malware policy.

    Attributes:
        metadata: Metadata associated with the check (inherited from Check).
    """

    def execute(self) -> List[CheckReportM365]:
        """
        Execute the check to verify if notifications for internal users sending malware are enabled.

        This method evaluates the Defender anti-malware policies to ensure internal sender notifications
        are properly configured.

        Returns:
            List[CheckReportM365]: A list of reports with the results of the check.
        """
        findings = []

        if defender_client.malware_policies:
            # Only Default Defender Malware Policy exists
            if not defender_client.malware_rules:
                policy = defender_client.malware_policies[0]

                report = CheckReportM365(
                    metadata=self.metadata(),
                    resource=policy,
                    resource_name=policy.identity,
                    resource_id=policy.identity,
                )

                if self._are_notifications_enabled(policy):
                    # Case 1: Default policy exists and has notifications enabled
                    report.status = "PASS"
                    report.status_extended = f"{policy.identity} is the only policy and notifications for internal users sending malware are enabled."
                else:
                    # Case 5: Default policy exists but doesn't have notifications enabled
                    report.status = "FAIL"
                    report.status_extended = f"{policy.identity} is the only policy and notifications for internal users sending malware are not enabled."
                findings.append(report)

            # Multiple Defender Malware Policies exist
            else:
                default_policy_well_configured = False

                for policy in defender_client.malware_policies:
                    # Preset security policies are scoped by protection policy rules, not filter rules
                    if (
                        not policy.is_default
                        and policy.identity not in defender_client.malware_rules
                    ):
                        continue
                    report = CheckReportM365(
                        metadata=self.metadata(),
                        resource=policy,
                        resource_name=policy.identity,
                        resource_id=policy.identity,
                    )

                    if policy.is_default:
                        if not self._are_notifications_enabled(policy):
                            # Case 4: Default policy not configured
                            report.status = "FAIL"
                            report.status_extended = (
                                f"{policy.identity} is the default policy and notifications for internal users sending malware are not enabled, "
                                "but it could be overridden by another well-configured Custom Policy."
                            )
                            findings.append(report)
                        else:
                            # Case 2: Default policy is properly configured
                            report.status = "PASS"
                            report.status_extended = (
                                f"{policy.identity} is the default policy and notifications for internal users sending malware are enabled, "
                                "but it could be overridden by another misconfigured Custom Policy."
                            )
                            default_policy_well_configured = True
                            findings.append(report)
                    else:
                        if not self._are_notifications_enabled(policy):
                            included_resources = []

                            if defender_client.malware_rules[policy.identity].users:
                                included_resources.append(
                                    f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}"
                                )
                            if defender_client.malware_rules[policy.identity].groups:
                                included_resources.append(
                                    f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}"
                                )
                            if defender_client.malware_rules[policy.identity].domains:
                                included_resources.append(
                                    f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}"
                                )

                            included_resources_str = "; ".join(included_resources)

                            if default_policy_well_configured:
                                # Case 3: Default policy is configured, custom one isn't
                                report.status = "FAIL"
                                report.status_extended = (
                                    f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, "
                                    f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
                                    "However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected."
                                )
                                findings.append(report)
                            else:
                                # Case 5: Neither default nor custom policy is properly configured
                                report.status = "FAIL"
                                report.status_extended = (
                                    f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, "
                                    f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
                                    "Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
                                )
                                findings.append(report)
                        else:
                            included_resources = []

                            if defender_client.malware_rules[policy.identity].users:
                                included_resources.append(
                                    f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}"
                                )
                            if defender_client.malware_rules[policy.identity].groups:
                                included_resources.append(
                                    f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}"
                                )
                            if defender_client.malware_rules[policy.identity].domains:
                                included_resources.append(
                                    f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}"
                                )

                            included_resources_str = "; ".join(included_resources)

                            if default_policy_well_configured:
                                # Case 2: Both default and custom policies are properly configured
                                report.status = "PASS"
                                report.status_extended = (
                                    f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, "
                                    f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
                                    "Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected."
                                )
                                findings.append(report)
                            else:
                                # Case 6: Default policy not configured, custom policy is
                                report.status = "PASS"
                                report.status_extended = (
                                    f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, "
                                    f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
                                    "However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
                                )
                                findings.append(report)

        return findings

    def _are_notifications_enabled(self, policy) -> bool:
        if (
            not policy.is_default
            and policy.identity in defender_client.malware_rules
            and defender_client.malware_rules[policy.identity].state.lower()
            != "enabled"
        ):
            return False

        return (
            policy.enable_internal_sender_admin_notifications
            and policy.internal_sender_admin_address
        )