{
  "id": "CB-M365-AUTH-045",
  "standard": "m365",
  "version": "main",
  "url": "https://baselines.cirsec.org/b/m365/CB-M365-AUTH-045",
  "json": "https://baselines.cirsec.org/b/m365/CB-M365-AUTH-045.json",
  "yaml": "https://baselines.cirsec.org/b/m365/CB-M365-AUTH-045.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-AUTH-045",
    "title": "Harden directory synchronization against cloud account takeover from Active Directory",
    "finding": {
      "title": "Directory synchronization lets on-premises objects take over cloud accounts",
      "description": "An attacker with rights in Active Directory can match a crafted object to an existing cloud account, including an administrator, and set its password."
    },
    "status": "active",
    "profiles": [
      "baseline"
    ],
    "risk": {
      "severity": "high"
    },
    "assessment": "manual",
    "tags": [
      "hybrid",
      "entra-connect",
      "soft-match",
      "hard-match",
      "privileged-access",
      "krbtgt"
    ],
    "applicability": {
      "requires": [
        "Identities synchronized from Active Directory (Microsoft Entra Connect or Cloud Sync)"
      ]
    },
    "description": "Directory synchronization is configured so that Active Directory cannot be used to take over cloud\nidentities:\n\n1. `BlockSoftMatchEnabled` is `true`: an on-premises object is never joined to an existing cloud\n   account on its primary SMTP address or UPN. It is turned off only for the duration of a planned\n   migration, then on again.\n2. `BlockCloudObjectTakeoverThroughHardMatchEnabled` is `true`: a cloud-managed account cannot be\n   taken over by an on-premises object with a matching immutable ID.\n3. The temporary bypass `allowOnPremUpdateOfOnPremisesObjectIdentifierEnabled` is `false`.\n4. The `krbtgt_AzureAD` account (Microsoft Entra Kerberos key object) is not in the\n   synchronization scope.\n5. The sync identity is protected: application-based authentication (Microsoft Entra Connect\n   2.5.76 or later), or, for a legacy user-based directory synchronization account, exclusion from\n   user Conditional Access policies combined with a policy that restricts it to the sync servers'\n   egress addresses. The sync servers are managed as Tier 0.\n",
    "rationale": "Soft and hard matching were designed for migrations, but they let whoever controls Active\nDirectory (or the sync server) attach an object to a cloud-only account, including a Global\nAdministrator, then push a known password through password hash synchronization. Synchronizing\n`krbtgt_AzureAD` exposes the key used to issue Kerberos tickets for cloud Kerberos trust. The sync\naccount has broad write rights on the directory and is a known pivot from on-premises to cloud.\n",
    "impact": "With soft matching blocked, new hybrid joined devices can fail with an InvalidSoftMatch error, and\nmigrations that rely on SMTP or UPN matching need the block lifted temporarily. Moving to\napplication-based authentication needs a Microsoft Entra Connect upgrade and a check with\n`Get-ADSyncEntraConnectorCredential`.\n",
    "notes": "Since July 2026, Microsoft blocks hard matches on accounts that hold or are eligible for privileged\nroles, or already have an `onPremisesObjectIdentifier`; the bypass flag in point 3 removes that\nprotection for the whole tenant. Cloud-only administrator accounts (CB-M365-ADMIN domain) remain\nthe main defense.\n",
    "audit": {
      "manual": "1. In PowerShell (Microsoft Graph, scope `OnPremDirectorySynchronization.Read.All`, role at\n   least Global Reader):\n   `Get-MgDirectoryOnPremiseSynchronization | Select-Object -ExpandProperty Features | Format-List`\n   Check `BlockSoftMatchEnabled : True`, `BlockCloudObjectTakeoverThroughHardMatchEnabled : True`\n   and, under `AdditionalProperties`, `allowOnPremUpdateOfOnPremisesObjectIdentifierEnabled : False`.\n2. In the Microsoft Entra admin center (https://entra.microsoft.com), browse to **Entra ID** >\n   **Users**, search for `krbtgt_AzureAD` and check that no synchronized user with that name\n   exists (**On-premises sync enabled** = **No** or no result).\n3. On each Microsoft Entra Connect server, run `Get-ADSyncEntraConnectorCredential` (read-only)\n   and check that `ConnectorIdentityType` is `Application`. Otherwise, browse to **Entra ID** >\n   **Roles & admins** > **Directory Synchronization Accounts**, note the user accounts, and check\n   in **Conditional Access** that a policy restricts them to trusted locations.\n4. Fail if soft or hard matching is not blocked, if the bypass flag is on, if `krbtgt_AzureAD`\n   is synchronized, or if a user-based sync account is unrestricted.\n"
    },
    "remediation": {
      "manual": "1. Block soft and hard matching (Microsoft Graph, scope\n   `OnPremDirectorySynchronization.ReadWrite.All`, Hybrid Identity Administrator):\n   `$s = Get-MgDirectoryOnPremiseSynchronization;\n   $s.Features.BlockSoftMatchEnabled = $true;\n   $s.Features.BlockCloudObjectTakeoverThroughHardMatchEnabled = $true;\n   Update-MgDirectoryOnPremiseSynchronization -OnPremisesDirectorySynchronizationId $s.Id -Features $s.Features`\n2. If the bypass flag is on and the remediation it was opened for is finished, set\n   `allowOnPremUpdateOfOnPremisesObjectIdentifierEnabled` to `false` the same way.\n3. Exclude `krbtgt_AzureAD` from synchronization: in the Microsoft Entra Connect wizard, filter\n   out its OU or the object, or add a sync rule that excludes it; run a delta sync and delete the\n   synchronized copy in Entra ID if one exists.\n4. Upgrade Microsoft Entra Connect and switch the connector to application-based\n   authentication; then remove the legacy directory synchronization account or its role.\n5. Until then, restrict the user-based sync account with a Conditional Access policy that blocks\n   it outside the sync servers' egress IP addresses.\n",
      "rollback": "Set `BlockSoftMatchEnabled` to `false` only for the duration of a planned soft-match migration,\nand set it back to `true` afterwards.\n"
    },
    "references": [
      {
        "title": "Microsoft Entra Connect Sync service features and configuration",
        "url": "https://learn.microsoft.com/entra/identity/hybrid/connect/how-to-connect-syncservice-features",
        "publisher": "Microsoft",
        "kind": "vendor-doc",
        "accessed": "2026-10-24"
      },
      {
        "title": "Configure Microsoft Entra Connect for an existing tenant",
        "url": "https://learn.microsoft.com/entra/identity/hybrid/connect/how-to-connect-install-existing-tenant",
        "publisher": "Microsoft",
        "kind": "vendor-doc",
        "accessed": "2026-10-24"
      },
      {
        "title": "Microsoft Entra Kerberos",
        "url": "https://learn.microsoft.com/entra/identity/authentication/kerberos",
        "publisher": "Microsoft",
        "kind": "vendor-doc",
        "accessed": "2026-10-24"
      },
      {
        "title": "Maester MT.1073 - Soft- and hard-matching of synchronized objects should be blocked",
        "url": "https://maester.dev/docs/tests/MT.1073",
        "publisher": "Maester",
        "kind": "tool",
        "accessed": "2026-10-24"
      }
    ],
    "mappings": [
      {
        "framework": "nist-800-53r5",
        "framework_version": "5.1.1",
        "id": "AC-2",
        "relation": "related"
      },
      {
        "framework": "nist-800-53r5",
        "framework_version": "5.1.1",
        "id": "CM-6",
        "relation": "related"
      }
    ],
    "threats": [
      {
        "framework": "mitre-attack",
        "id": "T1098"
      },
      {
        "framework": "mitre-attack",
        "id": "T1078.004"
      },
      {
        "framework": "mitre-attack",
        "id": "T1484.002"
      }
    ],
    "related_controls": [
      {
        "id": "CB-M365-AUTH-034",
        "type": "related"
      },
      {
        "id": "CB-M365-AUTH-044",
        "type": "related"
      },
      {
        "id": "CB-M365-ADMIN-001",
        "type": "related"
      }
    ],
    "authors": [
      {
        "name": "Alice",
        "github": "Sn0wAlice"
      }
    ],
    "introduced_in": "0.1.0",
    "created": "2026-10-24",
    "updated": "2026-10-24"
  }
}