Back to Checks
m365

Defender Outbound Spam policy disables mail forwarding

defender_antispam_outbound_policy_forwarding_disabled
Service: defenderSeverity: high
OfficialBuilt-inVerified
Categories:email-securitye3
Resource Type:NotDefined

Microsoft Defender for Office 365 outbound spam policies are evaluated to confirm that automatic mail forwarding is disabled in the default policy and in any custom policies applied to users, groups, or domains.

Risk

Allowing automatic forwarding enables covert data exfiltration, eroding confidentiality. Attackers or insiders can auto-route mail to external inboxes, persist access, evade monitoring, and harvest sensitive content (tickets, approvals, MFA codes), enabling lateral movement and fraud while reducing auditability.

Run this check with Prowler

Run in Prowler Cloud
Run
prowler m365 --checks defender_antispam_outbound_policy_forwarding_disabled

Recommendation

Disable automatic forwarding globally in outbound spam policies to enforce least privilege on data flows. If exceptions are required, restrict to named senders or domains, document approvals, and review regularly. Add DLP, alerts on new forwarding rules, and mailbox auditing for defense in depth.

Remediation

CLI

Set-HostedOutboundSpamFilterPolicy -Identity <policyName> -AutoForwardingMode Off

Other

1Sign in to https://security.microsoft.com
2Go to Email & collaboration > Policies & rules > Threat policies > Anti-spam
3Open Anti-spam outbound policy (Default) or the target custom policy
4Click Edit protection settings and set Automatic forwarding rules to Off - Forwarding is disabled, then Save
5For custom policies, ensure the policy Status is On (enabled); repeat for any additional policies

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_antispam_outbound_policy_forwarding_disabled(Check):
    """
    Check if the Defender Outbound Spam Policies are configured to disable mail forwarding.

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

    def execute(self) -> List[CheckReportM365]:
        """
        Execute the check to verify if the Defender Outbound Spam Policies disable mail forwarding.

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

        if defender_client.outbound_spam_policies:
            # Only Default Defender Outbound Spam Policy exists
            if not defender_client.outbound_spam_rules:
                policy = next(iter(defender_client.outbound_spam_policies.values()))

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

                if self._is_forwarding_disabled(policy):
                    # Case 1: Default policy exists and has forwarding disabled
                    report.status = "PASS"
                    report.status_extended = f"{policy.name} is the only policy and mail forwarding is disabled."
                else:
                    # Case 5: Default policy exists but allows forwarding
                    report.status = "FAIL"
                    report.status_extended = f"{policy.name} is the only policy and mail forwarding is allowed."
                findings.append(report)

            # Multiple Defender Outbound Spam Policies exist
            else:
                default_policy_well_configured = False

                for (
                    policy_name,
                    policy,
                ) in defender_client.outbound_spam_policies.items():
                    report = CheckReportM365(
                        metadata=self.metadata(),
                        resource=policy,
                        resource_name=policy_name,
                        resource_id=policy_name,
                    )

                    if policy.default:
                        if not self._is_forwarding_disabled(policy):
                            # Case 4: Default policy allows forwarding and there are other policies
                            report.status = "FAIL"
                            report.status_extended = (
                                f"{policy_name} is the default policy and mail forwarding is allowed, "
                                "but it could be overridden by another well-configured Custom Policy."
                            )
                            findings.append(report)
                        else:
                            # Case 2: Default policy disables forwarding and there are other policies
                            report.status = "PASS"
                            report.status_extended = (
                                f"{policy_name} is the default policy and mail forwarding is disabled, "
                                "but it could be overridden by another misconfigured Custom Policy."
                            )
                            default_policy_well_configured = True
                            findings.append(report)
                    else:
                        if not self._is_forwarding_disabled(policy):
                            included_resources = []

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

                            included_resources_str = "; ".join(included_resources)

                            if default_policy_well_configured:
                                # Case 3: Default policy disables forwarding but custom one doesn't
                                report.status = "FAIL"
                                report.status_extended = (
                                    f"Custom Outbound Spam policy {policy_name} allows mail forwarding and includes {included_resources_str}, "
                                    f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
                                    "However, the default policy disables mail forwarding, so entities not included by this custom policy could be correctly protected."
                                )
                                findings.append(report)
                            else:
                                # Case 5: Neither default nor custom policies disable forwarding
                                report.status = "FAIL"
                                report.status_extended = (
                                    f"Custom Outbound Spam policy {policy_name} allows mail forwarding and includes {included_resources_str}, "
                                    f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
                                    "Also, the default policy allows mail forwarding, so entities not included by this custom policy could not be correctly protected."
                                )
                                findings.append(report)
                        else:
                            included_resources = []

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

                            included_resources_str = "; ".join(included_resources)

                            if default_policy_well_configured:
                                # Case 2: Both default and custom policies disable forwarding
                                report.status = "PASS"
                                report.status_extended = (
                                    f"Custom Outbound Spam policy {policy_name} disables mail forwarding and includes {included_resources_str}, "
                                    f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
                                    "Also, the default policy disables mail forwarding, so entities not included by this custom policy could still be correctly protected."
                                )
                                findings.append(report)
                            else:
                                # Case 6: Default policy allows forwarding, custom policy disables it
                                report.status = "PASS"
                                report.status_extended = (
                                    f"Custom Outbound Spam policy {policy_name} disables mail forwarding and includes {included_resources_str}, "
                                    f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
                                    "However, the default policy allows mail forwarding, so entities not included by this custom policy could not be correctly protected."
                                )
                                findings.append(report)

        return findings

    def _is_forwarding_disabled(self, policy) -> bool:
        """
        Check if mail forwarding is disabled in the policy.

        Args:
            policy: The outbound spam policy to check.

        Returns:
            bool: True if mail forwarding is disabled, False otherwise.
        """
        return (
            policy.default
            or defender_client.outbound_spam_rules[policy.name].state.lower()
            == "enabled"
        ) and policy.auto_forwarding_mode == "Off"