{
  "id": "CB-M365-MAIL-037",
  "standard": "m365",
  "version": "main",
  "url": "https://baselines.cirsec.org/b/m365/CB-M365-MAIL-037",
  "json": "https://baselines.cirsec.org/b/m365/CB-M365-MAIL-037.json",
  "yaml": "https://baselines.cirsec.org/b/m365/CB-M365-MAIL-037.yml",
  "profiles_effective": [
    "hardened"
  ],
  "license": "Text CC BY 4.0, code Apache-2.0",
  "attribution": "CIRSEC Baselines, https://baselines.cirsec.org",
  "control": {
    "id": "CB-M365-MAIL-037",
    "title": "Scope application access to mailboxes with RBAC for Applications",
    "finding": {
      "title": "Applications with mail permissions can access every mailbox in the organization",
      "description": "An application granted Mail, Calendars or full mailbox permissions at tenant level can read or send from any mailbox, including executives', if its credentials leak."
    },
    "status": "active",
    "profiles": [
      "hardened"
    ],
    "risk": {
      "severity": "high"
    },
    "assessment": "manual",
    "tags": [
      "exchange-online",
      "applications",
      "rbac-for-applications",
      "graph-permissions",
      "least-privilege"
    ],
    "description": "Applications that use application permissions on mailbox data (Microsoft Graph `Mail.*`,\n`MailboxSettings.*`, `Calendars.*`, `Contacts.*`, or Exchange `full_access_as_app`) get them\nthrough **RBAC for Applications** in Exchange Online, limited to the mailboxes they need by a\nmanagement scope or administrative unit, and no longer through a tenant-wide grant in Microsoft\nEntra ID.\n\nOlder application access policies (`New-ApplicationAccessPolicy`) are acceptable while they are\nmigrated, provided every such application is restricted to a group.\n",
    "rationale": "Tenant-wide mail permissions turn one application secret into a key to every mailbox, and\nattackers look for exactly these applications after compromising a tenant. Scoping limits the\ndamage to the mailboxes the application really serves, and Exchange shows the scope in one place.\nEntra and Exchange grants add up, so the scope only works once the Entra grant is removed.\n",
    "impact": "Each application must be reviewed with its owner to define the mailboxes it needs. Removing the\nEntra grant before the RBAC assignment is in place breaks the application; test with\n`Test-ServicePrincipalAuthorization` first.\n",
    "audit": {
      "manual": "1. Sign in to the Microsoft Entra admin center (https://entra.microsoft.com) as at least a Global\n   Reader. Browse to **Entra ID** > **Enterprise apps**, and for each application open\n   **Security** > **Permissions** > **Admin consent**: note the applications that hold application\n   permissions on Microsoft Graph `Mail.*`, `MailboxSettings.*`, `Calendars.*`, `Contacts.*` or\n   Office 365 Exchange Online `full_access_as_app`.\n2. In Exchange Online PowerShell (read-only):\n   ```powershell\n   Get-ServicePrincipal | Format-Table DisplayName, AppId, ObjectId\n   Get-ManagementRoleAssignment -RoleAssigneeType ServicePrincipal |\n     Format-Table RoleAssigneeName, Role, CustomResourceScope, RecipientWriteScope\n   Get-ApplicationAccessPolicy | Format-Table AppId, AccessRight, ScopeName\n   ```\n3. Fail if an application holds a tenant-wide mailbox permission in Entra ID with no application\n   access policy restricting it, or if an RBAC for Applications assignment has no scope.\n"
    },
    "remediation": {
      "manual": "1. With each application owner, list the mailboxes it needs and put them in a management scope\n   (for example a filter on a custom attribute) or an administrative unit.\n2. In Exchange Online PowerShell (Exchange Administrator):\n   ```powershell\n   New-ServicePrincipal -AppId <app id> -ObjectId <enterprise app object id> -DisplayName \"<app>\"\n   New-ManagementScope -Name \"<app> mailboxes\" -RecipientRestrictionFilter \"CustomAttribute10 -eq '<app>'\"\n   New-ManagementRoleAssignment -App <app id> -Role \"Application Mail.Read\" -CustomResourceScope \"<app> mailboxes\"\n   Test-ServicePrincipalAuthorization -Identity <app id> -Resource <mailbox>\n   ```\n3. Once the test passes, remove the tenant-wide permission from the application in the Entra\n   admin center (**Enterprise apps** > the app > **Permissions** > **Revoke permission**, Cloud\n   Application Administrator or Privileged Role Administrator).\n",
      "rollback": "Grant the Entra application permission again with admin consent while the scope is fixed.\n"
    },
    "references": [
      {
        "title": "Role Based Access Control for Applications in Exchange Online",
        "url": "https://learn.microsoft.com/exchange/permissions-exo/application-rbac",
        "publisher": "Microsoft",
        "kind": "vendor-doc",
        "accessed": "2026-10-24"
      },
      {
        "title": "New-ApplicationAccessPolicy",
        "url": "https://learn.microsoft.com/powershell/module/exchangepowershell/new-applicationaccesspolicy",
        "publisher": "Microsoft",
        "kind": "vendor-doc",
        "accessed": "2026-10-24"
      },
      {
        "title": "Maester MT.1058 - Exchange application access policies must be configured",
        "url": "https://maester.dev/docs/tests/MT.1058",
        "publisher": "Maester",
        "kind": "tool",
        "accessed": "2026-10-24"
      }
    ],
    "mappings": [
      {
        "framework": "nist-800-53r5",
        "framework_version": "5.1.1",
        "id": "AC-6",
        "relation": "related"
      },
      {
        "framework": "nist-800-53r5",
        "framework_version": "5.1.1",
        "id": "AC-3",
        "relation": "related"
      }
    ],
    "threats": [
      {
        "framework": "mitre-attack",
        "id": "T1114.002"
      },
      {
        "framework": "mitre-attack",
        "id": "T1528"
      }
    ],
    "related_controls": [
      {
        "id": "CB-M365-MAIL-011",
        "type": "related"
      },
      {
        "id": "CB-M365-APPS-011",
        "type": "related"
      },
      {
        "id": "CB-M365-APPS-002",
        "type": "related"
      }
    ],
    "authors": [
      {
        "name": "Alice",
        "github": "Sn0wAlice"
      }
    ],
    "introduced_in": "0.1.0",
    "created": "2026-10-24",
    "updated": "2026-10-24"
  }
}