Existing check search
Provider
Microsoft 365
New provider name
No response
Service or product area
exchange
Suggested check name
exchange_mailbox_primary_smtp_uses_custom_domain
Context and goal
- Security condition to validate: Every user-facing Exchange Online mailbox in the tenant uses a primary SMTP address on a verified custom domain — never the default
*.onmicrosoft.com routing domain.
- Why it matters: The
*.onmicrosoft.com domain is the routing domain Microsoft assigns to every tenant on creation; it is not intended for ongoing day-to-day mail. Mailboxes that still send and receive on this domain leak the internal tenant identifier in every From: header (helping attackers fingerprint the tenant for spear-phishing), bypass DMARC/DKIM hardening that customers deploy on their custom domains, and frequently get treated as low-trust by recipients' anti-phishing engines. Microsoft's own admin guidance recommends moving every mailbox onto a verified custom domain after onboarding and reserving the .onmicrosoft.com address as a fallback.
- Resource involved: Exchange Online mailboxes (
Get-Mailbox) and their PrimarySmtpAddress.
Expected behavior
- Resource or scope to evaluate: All recipient-facing mailboxes returned by
Get-Mailbox -ResultSize Unlimited of types UserMailbox, SharedMailbox, RoomMailbox, and EquipmentMailbox. For each, inspect PrimarySmtpAddress.
- PASS when: every evaluated mailbox's
PrimarySmtpAddress resolves to a domain that is not under *.onmicrosoft.com. Empty tenants (no mailboxes) also PASS.
- FAIL when: at least one evaluated mailbox has
PrimarySmtpAddress under *.onmicrosoft.com. The finding should report the mailbox Identity, RecipientTypeDetails, and the offending PrimarySmtpAddress.
- MANUAL when: Exchange Online PowerShell is unavailable for the run — the check cannot complete and should report MANUAL with a status message asking the operator to enable EXO PowerShell.
- Exclusions / edge cases:
- Skip system-generated mailboxes by recipient type:
DiscoveryMailbox, ArbitrationMailbox, AuditLogMailbox, MonitoringMailbox, AuxAuditLogMailbox, and any mailbox tagged SystemMailbox. Those are managed by Microsoft and routinely keep the .onmicrosoft.com primary address by design.
- The check intentionally does not verify that secondary
EmailAddresses are also off .onmicrosoft.com. The policy concern is the primary (the address used for outbound mail and From: header). Audit of secondary addresses can be a follow-up.
References
Suggested severity
Low
Additional implementation notes
- Existing patterns to follow: Sibling checks
exchange_user_mailbox_auditing_enabled and exchange_shared_mailbox_sign_in_disabled already enumerate mailboxes via the existing Exchange Online PowerShell wiring in prowler/providers/m365/services/exchange/exchange_service.py. Reuse that same enumeration; expose RecipientTypeDetails and PrimarySmtpAddress on the loaded mailbox model if not already present.
- Permissions / scopes: No additional permissions beyond what the
exchange service already requires (Exchange Online PowerShell access). No Microsoft Graph permissions are needed for this check.
- PowerShell IS required; mailbox listings are not exposed via Microsoft Graph in a way that gives
PrimarySmtpAddress reliably across all recipient types.
- Exclusion list constant: Define the system-mailbox
RecipientTypeDetails exclusion list as a module-level constant so it is easy to extend if Microsoft introduces new recipient subtypes.
- Metadata: follow the Exchange metadata schema used by sibling checks under
exchange/. Set ResourceType to microsoft.exchange/mailboxes.
Existing check search
Provider
Microsoft 365
New provider name
No response
Service or product area
exchange
Suggested check name
exchange_mailbox_primary_smtp_uses_custom_domainContext and goal
*.onmicrosoft.comrouting domain.*.onmicrosoft.comdomain is the routing domain Microsoft assigns to every tenant on creation; it is not intended for ongoing day-to-day mail. Mailboxes that still send and receive on this domain leak the internal tenant identifier in every From: header (helping attackers fingerprint the tenant for spear-phishing), bypass DMARC/DKIM hardening that customers deploy on their custom domains, and frequently get treated as low-trust by recipients' anti-phishing engines. Microsoft's own admin guidance recommends moving every mailbox onto a verified custom domain after onboarding and reserving the.onmicrosoft.comaddress as a fallback.Get-Mailbox) and theirPrimarySmtpAddress.Expected behavior
Get-Mailbox -ResultSize Unlimitedof typesUserMailbox,SharedMailbox,RoomMailbox, andEquipmentMailbox. For each, inspectPrimarySmtpAddress.PrimarySmtpAddressresolves to a domain that is not under*.onmicrosoft.com. Empty tenants (no mailboxes) also PASS.PrimarySmtpAddressunder*.onmicrosoft.com. The finding should report the mailboxIdentity,RecipientTypeDetails, and the offendingPrimarySmtpAddress.DiscoveryMailbox,ArbitrationMailbox,AuditLogMailbox,MonitoringMailbox,AuxAuditLogMailbox, and any mailbox taggedSystemMailbox. Those are managed by Microsoft and routinely keep the.onmicrosoft.comprimary address by design.EmailAddressesare also off.onmicrosoft.com. The policy concern is the primary (the address used for outbound mail and From: header). Audit of secondary addresses can be a follow-up.References
onmicrosoft.comprimary domain guidance): https://learn.microsoft.com/en-us/microsoft-365/admin/setup/domains-faqGet-Mailbox: https://learn.microsoft.com/en-us/powershell/module/exchange/get-mailboxSuggested severity
Low
Additional implementation notes
exchange_user_mailbox_auditing_enabledandexchange_shared_mailbox_sign_in_disabledalready enumerate mailboxes via the existing Exchange Online PowerShell wiring inprowler/providers/m365/services/exchange/exchange_service.py. Reuse that same enumeration; exposeRecipientTypeDetailsandPrimarySmtpAddresson the loaded mailbox model if not already present.exchangeservice already requires (Exchange Online PowerShell access). No Microsoft Graph permissions are needed for this check.PrimarySmtpAddressreliably across all recipient types.RecipientTypeDetailsexclusion list as a module-level constant so it is easy to extend if Microsoft introduces new recipient subtypes.exchange/. SetResourceTypetomicrosoft.exchange/mailboxes.