{
  "id": "CB-M365-MAIL-016",
  "standard": "m365",
  "version": "main",
  "url": "https://baselines.cirsec.org/b/m365/CB-M365-MAIL-016",
  "json": "https://baselines.cirsec.org/b/m365/CB-M365-MAIL-016.json",
  "yaml": "https://baselines.cirsec.org/b/m365/CB-M365-MAIL-016.yml",
  "profiles_effective": [
    "baseline",
    "hardened"
  ],
  "license": "Text CC BY 4.0, code Apache-2.0",
  "attribution": "CIRSEC Baselines, https://baselines.cirsec.org",
  "control": {
    "id": "CB-M365-MAIL-016",
    "title": "Publish an enforcing DMARC policy with reporting for every domain",
    "finding": {
      "title": "Some domains have no DMARC policy, or one that does not quarantine or reject spoofed mail",
      "description": "Messages that forge the organization's domains in the visible From address can still reach recipients, and nobody receives reports about the forgery."
    },
    "status": "active",
    "profiles": [
      "baseline"
    ],
    "risk": {
      "severity": "high"
    },
    "assessment": "manual",
    "tags": [
      "dns",
      "dmarc",
      "email-authentication",
      "spoofing",
      "domains"
    ],
    "description": "Every domain the organization owns publishes a DMARC TXT record at `_dmarc.<domain>` with:\n\n- `p={{ dmarc_policy }}` for domains that send mail, and `p=reject` for domains that never send\n  mail (parked domains);\n- no `pct` tag, or `pct=100`;\n- a subdomain policy (`sp`) that is absent or not weaker than `p`;\n- aggregate reports (`rua`) sent to {{ dmarc_report_address }}.\n\nSPF (CB-M365-MAIL-014) and DKIM (CB-M365-MAIL-015) must pass and align for legitimate senders\nbefore the policy is enforced.\n",
    "rationale": "DMARC is the only standard that protects the From address users actually see. With `p=none`,\nreceivers only report forgeries; with `quarantine` or `reject` they stop them, which protects\nemployees, customers and partners from phishing that uses the organization's name. Reports show\nforgery attempts and forgotten legitimate senders.\n",
    "impact": "Legitimate senders that fail SPF and DKIM alignment (a forgotten marketing tool, a partner that\nsends on the organization's behalf) see their messages quarantined or rejected. Start with\n`p=none`, read the reports for a few weeks, fix the senders, then move to `quarantine` and\n`reject`. A third-party DMARC report service makes the reports usable.\n",
    "parameters": [
      {
        "name": "dmarc_policy",
        "type": "enum",
        "description": "DMARC policy required for domains that send mail.",
        "default": "quarantine",
        "profile_defaults": {
          "hardened": "reject"
        },
        "allowed": [
          "quarantine",
          "reject"
        ]
      },
      {
        "name": "dmarc_report_address",
        "type": "string",
        "description": "Mailbox or report service that receives DMARC aggregate reports.",
        "default": "a mailbox or DMARC report service monitored by the organization"
      }
    ],
    "audit": {
      "manual": "1. List the domains as in CB-M365-MAIL-014 (Microsoft 365 admin center > **Settings** >\n   **Domains**, plus registrar inventory).\n2. For each domain, query DNS (no tenant role needed):\n   ```powershell\n   Get-AcceptedDomain | ForEach-Object {\n     Resolve-DnsName -Name \"_dmarc.$($_.DomainName)\" -Type TXT -ErrorAction SilentlyContinue | Select-Object Name, Strings\n   }\n   ```\n3. Fail if a domain has no DMARC record, if a sending domain's policy is weaker than\n   `{{ dmarc_policy }}`, if a parked domain is not `p=reject`, if `pct` is below 100, if `sp` is\n   weaker than the required policy, or if there is no `rua` address.\n"
    },
    "remediation": {
      "manual": "1. Publish a monitoring record first, for example\n   `v=DMARC1; p=none; rua=mailto:dmarc@example.com`, and analyze the aggregate reports.\n2. Fix SPF and DKIM for every legitimate sender found in the reports.\n3. At the DNS hosting provider, update the TXT record at `_dmarc.<domain>`:\n   ```text\n   v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com\n   ```\n   then `p=reject` where the parameter requires it.\n4. For parked domains, publish `v=DMARC1; p=reject` directly.\n",
      "rollback": "Lower the policy to `p=none` while a delivery problem is investigated.\n"
    },
    "references": [
      {
        "title": "Set up DMARC to validate the From address domain for cloud senders",
        "url": "https://learn.microsoft.com/defender-office-365/email-authentication-dmarc-configure",
        "publisher": "Microsoft",
        "kind": "vendor-doc",
        "accessed": "2026-10-24"
      },
      {
        "title": "RFC 7489: Domain-based Message Authentication, Reporting, and Conformance (DMARC)",
        "url": "https://www.rfc-editor.org/rfc/rfc7489",
        "publisher": "IETF",
        "kind": "rfc",
        "accessed": "2026-10-24"
      },
      {
        "title": "CISA SCuBA Exchange Online baseline",
        "url": "https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/baselines/exo.md",
        "publisher": "CISA",
        "kind": "standard",
        "accessed": "2026-10-24"
      }
    ],
    "mappings": [
      {
        "framework": "cisa-scuba-m365",
        "framework_version": "2.0.0",
        "id": "MS.EXO.4.1v1",
        "relation": "equivalent"
      },
      {
        "framework": "cisa-scuba-m365",
        "framework_version": "2.0.0",
        "id": "MS.EXO.4.2v1",
        "relation": "looser",
        "note": "Our baseline accepts p=quarantine; the hardened value p=reject matches SCuBA."
      },
      {
        "framework": "cisa-scuba-m365",
        "framework_version": "2.0.0",
        "id": "MS.EXO.4.4v1",
        "relation": "equivalent"
      },
      {
        "framework": "nist-800-53r5",
        "framework_version": "5.1.1",
        "id": "SI-8",
        "relation": "related"
      },
      {
        "framework": "nist-800-53r5",
        "framework_version": "5.1.1",
        "id": "SI-4(5)",
        "relation": "related"
      }
    ],
    "threats": [
      {
        "framework": "mitre-attack",
        "id": "T1566"
      }
    ],
    "related_controls": [
      {
        "id": "CB-M365-MAIL-014",
        "type": "related"
      },
      {
        "id": "CB-M365-MAIL-015",
        "type": "related"
      },
      {
        "id": "CB-M365-MAIL-017",
        "type": "related"
      }
    ],
    "authors": [
      {
        "name": "Alice",
        "github": "Sn0wAlice"
      }
    ],
    "introduced_in": "0.1.0",
    "created": "2026-10-24",
    "updated": "2026-10-24"
  }
}