Read-Only Is a Lie: An Entra ID Privilege Escalation

Ilan Kalendarov, Security Research Team Lead
Ben Zamir, Security Researcher
Elad Beber, Security Researcher
A user with nothing but the Global Reader directory role, no Azure RBAC, no Connect Health assignment and no foothold anywhere on-premises, issues a single HTTPS GET to Azure Resource Manager and receives back a live client secret: the credential your on-premises hybrid identity agent uses to authenticate to Microsoft’s cloud.
Sixty seconds later that “read-only auditor” is holding an agent bearer token, an Event Hub publisher key and a write-scoped SAS into Microsoft’s own storage, while the real agent on your domain controller has been silently locked out.
Cymulate Research Lab discovered this issue as part of its ongoing work to build and maintain the most comprehensive attack library for Cymulate Exposure Validation. That research requires continuous analysis of real-world attacker behavior, emerging techniques and weaknesses in widely used enterprise technologies. Each discovery helps Cymulate turn threat intelligence into safe, repeatable validation scenarios that security teams can use to test controls, measure exposure and reduce risk before attackers take advantage.
For Security Leaders
Global Reader and Security Reader are roles you never hand out sparingly, but when you do you want someone to be able to look but never touch. Internal audit gets them. GRC analysts get them. SOC tier-1 gets them. Your MSSP gets them. The compliance scanner’s service principal gets them. Microsoft’s own documentation describes Global Reader as the role that “can read everything that a Global Administrator can, but not update anything.” By design and by reputation, these are the most straight-forward grants in Microsoft Entra ID.
This research shows that in a hybrid identity environment, they are not read-only. A principal holding only one of those roles can retrieve the AgentKey: the client secret belonging to the Microsoft Entra Connect Health agent running on your on-premises sync server, AD FS farm, or domain controllers. That is a credential Microsoft’s own agent protects with DPAPI on the host where it lives. Over the API, it is handed to a read-only role on request.
Once the attacker has it, they stop being an auditor. They authenticate to Microsoft’s Connect Health service as your agent, obtain the agent’s telemetry publishing keys, and gain write access into the pipeline that feeds your hybrid identity monitoring. And because the act of reading the credential rotates it, the legitimate agent on your server is knocked offline. This is a read operation that produces a denial of monitoring.
The blast radius is not one server. The enumeration path has no per-object authorization, which means one read-only account can walk the entire Connect Health fleet and collect every member’s agent credential in a single pass.
Two things make this worth your attention beyond the specific bug. First, the Global Reader entry privilege is one of the most widely and casually delegated roles in the Microsoft cloud. Second, the access path, in which an Entra directory role directly authorizes an Azure Resource Manager operation, is invisible to the tooling most organizations use to audit privilege. Your Azure RBAC access review will not show it. BloodHound and AzureHound do not model the edge. If you have been reasoning about “read-only” as an inherently safe grant, this is the case that breaks the assumption.
Vulnerability at a Glance
| Affected service | Microsoft Entra Connect Health (formerly Azure AD Connect Health) |
| Resource provider | Microsoft.ADHybridHealthService (tenant-level ARM provider) |
| Affected operation | services/servicemembers/credentials/read and the addsservices sibling |
| Vulnerability class | Elevation of Privilege via improper authorization |
| CWE | CWE-269 (Improper Privilege Management), CWE-200 (Exposure of Sensitive Information), CWE-284 (Improper Access Control) |
| Entry privilege | A single read-only Entra directory role: Security Reader (the floor), Global Reader, or Hybrid Identity Administrator. Zero Azure RBAC. No on-premises access. |
| Impact | Theft of a live, reusable agent client secret, leading to full impersonation of the on-premises health agent, possession of Event Hub publisher and write-scoped Blob SAS credentials, and denial of hybrid identity monitoring |
| CVSS 3.1 | 8.3 / High (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:L) |
| Service | Entra Connect Sync, AD FS, AD DS |
How the Research Started
The Cymulate Research Lab had been mapping the seams of hybrid identity: the places where the on-premises world and the Entra ID world have to trust each other, and the machinery Microsoft built to make that trust work. Hybrid identity is where the two halves of an enterprise directory meet, and meeting points have historically been where the interesting failures live. Golden SAML, DCSync-to-cloud pivots, syncjacking, PTA agent abuse. The pattern in all of them is the same. Something on-premises holds a credential that the cloud honors, and the entire security model rests on that credential being hard to reach.
So we started with a simple question. What does the cloud side of hybrid identity hand out, and to whom?
Microsoft Entra Connect Health seemed like an unremarkable place to start. It is the monitoring service, the thing that tells you your sync is running, your AD FS farm is healthy, your domain controllers are replicating. It ships as a lightweight agent installed alongside Entra Connect Sync, on AD FS and Web Application Proxy servers, or on domain controllers, and it phones home with telemetry. Nobody thinks of it as a security control. It is plumbing.
But plumbing needs credentials. And when we pulled apart the agent’s registration code, we found the credential it uses: a value the agent calls the AgentKey, fetched during registration and then immediately written to the registry under DPAPI protection. Microsoft’s own client code treats this thing as a secret worth encrypting at rest.
The natural follow-up question was where the agent gets it from during registration. The answer was an ARM endpoint:
GET https://management.azure.com/providers/Microsoft.ADHybridHealthService/
services/{serviceName}/servicemembers/{serviceMemberId}/credentials
?api-version=2014-01-01 And the authorization action behind it, per Microsoft’s own published permissions catalog:
Microsoft.ADHybridHealthService/services/servicemembers/credentials/read
That last word is where the research stopped being routine.
In Azure’s permission model, /read is not just a naming convention. It is a load-bearing security boundary. The built-in Reader role is defined, in its entirety, as:
"permissions": [{
"actions": ["*/read"],
"notActions": [],
"dataActions": [],
"notDataActions": []
}] A wildcard over every /read action in Azure, with no carve-outs. Which means the question answered itself. If an operation that returns a live client secret is named credentials/read, then by construction, every read-tier principal in the tenant already has permission to call it.
We had a hypothesis. What we needed was a lab and a disposable user.
What the Agent Actually Is, and Why Its Key Matters
Before the attack, it is worth being precise about what the AgentKey buys you, because the value of the finding lives entirely in that answer. Everything in this section is documented by Microsoft or was established publicly in 2021 by Dr. Nestori Syynimaa’s AADInternals research into the same agent.
The Microsoft Entra Connect Health agent runs on-premises. Per Microsoft’s installation documentation, it is installed automatically as part of Microsoft Entra Connect (version 2.5.79.0 or higher) on the sync server, on AD FS and Web Application Proxy servers in a federated deployment, and on domain controllers for AD DS monitoring. Its job is to collect health and diagnostic data and upload it to Microsoft’s cloud service, where it becomes the Connect Health dashboard and the alerting surface.
For AD FS deployments it becomes more than a dashboard. Connect Health processes the audit events generated by every AD FS server in the farm to produce the Risky IP report and the “Top 50 Users with failed Username/Password logins” report, which breaks failures down into categories including incorrect credentials, extranet lockout, expired password and disabled account. Identity and SOC teams use these as a detection source. That matters later, because it means the telemetry pipeline this vulnerability exposes is not just an operations feed. It is evidence.
To ship that data, the agent needs an identity. It has one, and it is assembled from three registry values on the host:
- Tenant ID, from HKLM:\SOFTWARE\Microsoft\ADHealthAgent\TenantId
- Machine ID, from HKLM:\SOFTWARE\Microsoft\Microsoft Online\Reporting\MonitoringAgent\MachineIdentity
- AgentKey, from HKLM:\SOFTWARE\Microsoft\ADHealthAgent\AgentKey, stored under DPAPI protection
Those become an ordinary OAuth client credentials pair. The client ID is {tenantId}_{machineId}, the two GUIDs joined by an underscore. The client secret is the AgentKey, a 344-character opaque string in our testing. Authentication does not go to Azure AD. It goes to Connect Health’s own token service:
POST https://s1.adhybridhealth.azure.com/oauth2/token
grant_type=client_credentials
client_id={tenantId}_{machineId}
client_secret={AgentKey}
resource=https://management.core.windows.net/The response is a bearer token that Microsoft’s Connect Health backend accepts as proof that you are that specific on-premises server. With it, an agent requests the two data-plane keys it needs to do its job: a BlobUploadKey, which returns a storage URL with a SAS token, and an EventHubPublisherKey, which returns a Service Bus endpoint with a SAS token.
So the AgentKey is not a config value. It is the entire authentication identity of a machine inside your identity infrastructure, condensed into a string. The client ID half is metadata that this vulnerability hands you for free. The secret half is the only thing standing between an attacker and being that machine.
There is one more piece of context that sharpens the contrast. Obtaining this credential the legitimate way, by registering an agent, is an administrative operation. Microsoft’s documentation requires a Global Administrator or Hybrid Identity Administrator account to run Register-MicrosoftEntraConnectHealthAgent. Registration is gated on the two highest privilege tiers in the tenant. Reading the credential that registration produces, as we will show, is gated on Security Reader.
Defect One: A Secret-Issuing Operation Wearing a /read
Azure has a well-established, deliberately designed pattern for this exact situation, and Microsoft documents it in unusually direct language.
When an Azure operation returns a credential, it is modeled as a POST action, never a /read. Storage account keys come from listKeys. Event Grid keys come from listKeys. Cosmos DB keys come from listKeys. Automation account keys come from a POST API. In every case the operation is deliberately excluded from the Reader role’s */read wildcard.
Microsoft is explicit about the mechanics:
“List Keys is a POST operation, and all POST operations are prevented when a ReadOnly lock is configured for the account.”
“The Azure Resource Manager Reader role permits users to view storage account resources, but not modify them. It doesn’t provide read permissions to data in Azure Storage, but only to account management resources.”
Source: Authorize access to data in the Azure portal, learn.microsoft.com
The Key Vault documentation states the boundary as a role definition. The built-in Key Vault Reader role can:
“Read metadata of key vaults and its certificates, keys, and secrets. Cannot read sensitive values such as secret contents or key material.”
Source: Provide access to Key Vault keys, certificates, and secrets with Azure role-based access control, learn.microsoft.com
And in the Azure Automation documentation, Microsoft describes the precise threat model that motivates the whole pattern. Read this one carefully, because it is describing the direct functional analog of this finding, an agent enrollment key reachable by a read-named role:
“The Built-in Reader role for the Automation Account can’t use the API GET /AUTOMATIONACCOUNTS/AGENTREGISTRATIONINFORMATION to fetch the Automation Account keys. This is a high privilege operation providing sensitive information that could pose a security risk of an unwanted malicious actor with low privileges who can get access to automation account keys and can perform actions with elevated privilege level.”
Source: Manage role permissions and security in Azure Automation, learn.microsoft.com
Microsoft has written down the rule, written down the reasoning, and enforced it across the platform.
Microsoft.ADHybridHealthService is the outlier. Its credential-issuing operation is named credentials/read, and Microsoft’s own permissions catalog describes it as “During server registration, this api is called to get the credentials for onboarding new servers.” The sibling AD DS action carries the same description for ADDomainService. An onboarding operation, filed under the read verb.
The consequence is mechanical. */read matches credentials/read. There is no notActions entry anywhere to stop it. Every read-tier principal inherits a live secret.
Defect Two: The Bridge Nobody Audits
We expected the exploit path to run through Azure RBAC. It does not, and the reason it does not is the second half of the story, and arguably the more important one.
Microsoft.ADHybridHealthService is a tenant-level provider. Look at its resource paths: there is no /subscriptions/{id}/ segment anywhere in them. They hang directly off /providers/. That means there is no subscription for Azure RBAC to be scoped against, and in practice the provider does not gate on Azure RBAC at all.
Instead it authorizes off the wids[] claim in the caller’s ARM token, the list of Microsoft Entra directory roles the caller holds.
We proved this with a differential test. Three principals, one endpoint:
| Caller | servicemembers/read | credentials/read |
| No role, no RBAC | 403 AuthorizationFailed | 403 AuthorizationFailed |
| Azure RBAC Reader at subscription scope (80s propagation) | 403 AuthorizationFailed | 403 AuthorizationFailed |
| Global Reader directory role, zero Azure RBAC | 200 | 200, AgentKey returned |
The Azure RBAC Reader, the principal whose role definition literally contains the wildcard that matches this action, is denied. The Entra directory reader, who holds no Azure RBAC of any kind, is allowed.
The provider is not consulting Azure RBAC. It is consulting a curated allowlist of directory roles. We mapped it:
ALLOWED: Global Reader, Security Reader, Security Administrator, Hybrid Identity Administrator, Global Administrator
DENIED: Security Operator, Helpdesk Administrator, Reports Reader, Directory Readers, no role
The DENY column is what makes this conclusive. If the access were a residual bug or a blanket grant, Directory Readers and Reports Reader would be through the door too. They are not. Somebody wrote this list on purpose. Security Reader is the floor, the least-privileged role in the tenant that reaches a hybrid agent credential.
This also sits awkwardly against Microsoft’s documented separation of the two planes:
“By default, Azure roles and Microsoft Entra roles don’t span Azure and Microsoft Entra ID.”
Source: Azure roles, Microsoft Entra roles, and classic subscription administrator roles, learn.microsoft.com
And it sits awkwardly against Connect Health’s own documented authorization model, which describes access purely in terms of the Azure RBAC roles assigned through the portal blade, characterizes the Reader capability as being able to “view all information (for example, view alerts) from the portal within Microsoft Entra Connect Health”, and states that “all other roles … have no impact to access within Microsoft Entra Connect Health.” Reading the agent’s client secret is not “view alerts”, and the read-only directory roles that actually reach the secret are not listed as having any access at all.
Then we checked whether this was a one-off. It is not.
We found the identical bridge in a second, unrelated provider, microsoft.aadiam, which backs Entra diagnostic settings:
- Directory-role-only principals with zero Azure RBAC: HTTP 200 (Global Admin, Global Reader, Security Admin, Security Reader, Reports Reader)
- Azure RBAC principals: HTTP 403, including a built-in Reader service principal whose */read wildcard literally contains the action, and a custom role granting the exact action by name. The same tokens succeeded against ordinary Azure RBAC resources in the same run.
Two providers, two independently curated allowlists. Reports Reader is allowed on microsoft.aadiam and denied on ADHybridHealthService. That divergence proves these are hand-maintained per-provider lists, which makes this a recurring design pattern, not a single mistake.
And here is the defensive problem. Mainstream privilege-audit tooling does not model a directory-role to ARM-data-plane edge. Your Azure RBAC access review will report that nobody has permissions on this provider. BloodHound will not draw the path. The access is real, it is exercisable, and it is invisible to the instruments you would normally use to find it.
The Attack, Step by Step
Step 1: Create the most harmless account you can imagine
We provision a fresh user and grant it exactly one thing, the Global Reader directory role (template ID f2ef992c-3afb-46b9-b7cf-a126ee74c451). Then we verify what it does not have:
[+] user created: gr-poc-...@{tenant}.onmicrosoft.com
Azure RBAC role assignments : 0
Connect Health assignments : none
Admin consent granted : none
On-premises access : none We sign in as that user, mint a delegated ARM token, and decode it to establish the load-bearing fact of the entire finding:
"wids": [ <Global Reader>, <Directory Readers> ]
"roles": <absent>
"aud": "https://management.core.windows.net/" Two read-only directory roles. No application roles. No Azure RBAC. This token belongs to an auditor and nothing more. Every subsequent step is performed with it.
Step 2: Enumerate the hybrid topology
Global Reader is enough to walk the provider:
GET /providers/Microsoft.ADHybridHealthService/services?api-version=2014-01-01
GET /providers/Microsoft.ADHybridHealthService/services/{serviceName}/servicemembers Back comes the map of the hybrid deployment: the service name, the serviceId, every serviceMemberId, and, critically, every machineId.
Two things are worth noting here.
The first is that this enumeration returns byte-identical results to what a Global Administrator sees. Same objects, same fields, same counts. There is no per-service or per-member ACL anywhere on this path. Our lab happened to have a single member, so the blast radius is determined by the authorization model rather than by our member count. In a production tenant running a sync server, an AD FS farm and AD DS monitoring, this single enumeration returns the whole fleet, and every one of them is a credential-theft target in the next step.
The second is that machineId is one half of the agent’s client ID, the value the real agent reads out of its own registry. The attacker now has it, for every agent, from a read-only role.
The response also volunteers the on-premises topology: forest and domain names, Active Directory naming-context distinguished names, the sync service account name, and the SQL backend behind Entra Connect. That alone is a reconnaissance gift for anyone planning an on-premises campaign.
Step 3: Ask for the credential
This is the whole vulnerability, and it is one request:
GET /providers/Microsoft.ADHybridHealthService/services/{serviceName}
/servicemembers/{serviceMemberId}/credentials?api-version=2014-01-01
Authorization: Bearer \<read-only auditor token>
HTTP/1.1 200 OK
{
"value": [{
"identifier": "AgentKey",
"credentialData": "<344 characters>",
...
}]
} A 200 OK and a live client secret, returned to a principal whose entire authorization consists of two read-only directory roles. This is the same value the agent on your server keeps under DPAPI, and the same value Microsoft requires a Global Administrator to obtain through the supported registration path.
One detail from the lab is worth calling out. We called this endpoint repeatedly and hashed each response. Every call returned a different key. The credential is minted fresh per read, which tells you two things. It is genuinely live, issuable secret material rather than a cached artifact. And the GET has a write side effect: it rotates the production agent’s key.
Which means the legitimate agent on the on-premises server, still holding the previous key, has just been locked out. Reading the credential is simultaneously a credential theft and a denial of monitoring. Recovery requires an administrator to re-register the agent, and the attacker, still holding nothing but a read-only role, can simply do it again.
Step 4: Become the agent
The attacker now has both halves of an agent identity: the machineId from Step 2, the AgentKey from Step 3. The exchange is a textbook client credentials grant:
POST https\://s1.adhybridhealth.azure.com/oauth2/token
grant\_type=client\_credentials
client\_id={tenantId}\_{machineId}
client\_secret={stolen AgentKey}
resource=https\://management.core.windows.net/
HTTP/1.1 200 OK
{ "access\_token": "<384 chars>", "expires\_in": 3599 } The privilege boundary has now been crossed. Before this request the attacker was a read-only cloud auditor. After it, Microsoft’s Connect Health backend believes the attacker is a specific on-premises server inside the victim’s identity infrastructure.
We confirmed the binding is real and not cosmetic. The same AgentKey paired with a randomly generated machine ID returns 400 Invalid credentials. The token is genuinely bound to the impersonated machine.
And because this is a client credentials grant against a long-lived secret, it is not a one-shot read. It is durable, refreshable impersonation for as long as the attacker holds the key.
Step 5: Collect the agent’s keys
Agents need to publish telemetry, so the Connect Health service hands its agents the keys to do it. The attacker, now indistinguishable from an agent, simply asks for them, using the same two endpoints the real agent uses:
GET https\://s1.adhybridhealth.azure.com/providers/Microsoft.ADHybridHealthService
/monitoringpolicies/{serviceId}/keys/EventHubPublisherKey
Authorization: Bearer \<agent token>
HTTP/1.1 200 OK
→ Event Hub publisher SAS
host : adhsprod...ehsyncia.servicebus.windows.net
audience : /{entity}/Publishers/{publisherId}
key name : RootManageSharedAccessKey
expires : +1 hour
GET .../monitoringpolicies/{serviceId}/keys/BlobUploadKey
HTTP/1.1 200 OK
→ Storage SAS, permissions sp=w (write)
→ adhsprod...aadsynciadata.blob.core.windows.net/{container}-{serviceId}We ran a control test specifically to make sure we were attributing this impact correctly. Can the read-only role reach these SAS keys directly, without the AgentKey? It cannot. Both endpoints reject the auditor token. These keys are reachable only through the impersonation, which is precisely why the credential theft is an elevation of privilege rather than merely an over-broad read.
Step 6: Write
A read-only role, by definition, cannot write anything. Here is what ours did.
Into the telemetry pipeline:
POST https\://{namespace}.servicebus.windows.net/{entity}
/Publishers/{publisherId}/messages
HTTP/1.1 201 Created Into Microsoft’s hybrid sync-data storage:
PUT https\://adhsprod...aadsynciadata.blob.core.windows.net
/{container}-{serviceId}/{blob}?\<sp=w SAS>
HTTP/1.1 201 Created Two 201 Created responses, both produced by an identity whose only permissions are read-only directory roles.
We verified the blob write was real rather than an acknowledgment artifact. A follow-up conditional PUT carrying If-None-Match: \ returned 409 Conflict, proving the object exists in Microsoft’s storage. Proof blobs written on one day were still present the next.
We also mapped the limits, because they matter for accurate severity. The SAS is write-only: GET, HEAD and List all return 403 AuthorizationPermissionMismatch, so there is no exfiltration or enumeration from the storage account. The issued SAS tokens are cryptographically tamper-resistant; adding read or list permission bits to the query string invalidates the signature and yields AuthenticationFailed. And the agent bearer token is an opaque token from the Connect Health token service, not an Azure AD token. {tenantId}\_{machineId} is not an Azure AD principal, so it does not pivot to Microsoft Graph, ARM, Key Vault, or general storage.
What is proven, and what we claim, is this: theft of a live agent credential by a read-only role, durable impersonation of an on-premises hybrid identity agent, possession of that agent’s telemetry publishing keys, authenticated writes into two Microsoft-hosted tenant data planes, and a denial of hybrid identity monitoring as a side effect of the read.
Step 7: Do it again, everywhere
The final step is the one that turns a bug into an exposure.
The defect is not confined to one resource collection. We proved the identical chain against the addsservices collection, the AD DS variant, where a Global-Reader-only principal with zero Azure RBAC received a live 344-character AgentKey, HTTP 200, minted fresh per read. We built that service member entirely through the ARM API; no domain controller was required to test it.
We proved it again on the AD FS variant. Here the entry bar dropped further: a Security Reader, not Global Reader, with zero Azure RBAC read the AD FS service member’s AgentKey and minted a working AD FS agent bearer token. That is the variant whose telemetry becomes the Risky IP and failed-sign-in reports.
Three service variants. One root cause. And because Step 2’s enumeration has no per-object authorization, a single read-only account sweeps all of them in one pass and walks away with the credential for every Connect Health agent in the tenant.
It is worth pausing on how much cheaper this is than the last time someone reached this credential. In 2021, Dr. Nestori Syynimaa demonstrated abuse of the same AgentKey and the same two SAS keys, and Microsoft serviced it. That research obtained the key by reading it out of the registry of an on-premises AD FS server, which required local administrator on a critical identity host: an attacker already inside the network and already owning the machine. This research reaches the same secret with a cloud account whose only permission is to look at things.
One scope note on that comparison. The 2021 work demonstrated forged events surfacing in the Azure AD sign-in logs. Testing that path in 2026, using both the REST transport and the faithful AMQP transport, with a positive control that surfaced within six minutes, our forged events were accepted at the transport layer but never surfaced in the sign-in logs. Microsoft appears to have hardened ingestion since 2021. We therefore do not claim sign-in-log spoofing as a working impact. What we claim is the credential theft and the agent impersonation, both of which are proven.
Disclosure Timeline
| Date | Event |
| 6 July 2026 | Reported to the Microsoft Security Response Center, with proof-of-concept script and video |
| 7 July 2026 | MSRC case opened |
| 15 July 2026 | Microsoft confirmed the reported behavior |
| 20 July 2026 | Severity assigned: Important |
| 10 August 2026 | Microsoft confirmed the issue is resolved, with rollout in progress |
Vendor Response
Microsoft confirmed the reported behavior nine days after submission and assigned it a severity of Important. The issue was reported resolved on 10 August 2026.
We want to acknowledge MSRC’s handling of the case. The behavior was confirmed quickly, the assessment was substantive, and the team engaged with the underlying authorization-modeling question rather than only with the single endpoint.
Regardless of the vendor fix, we recommend that organizations verify the following independently:
- That read-only directory role holders in your tenant can no longer retrieve Connect Health agent credentials. This is a single request to test, and it is worth confirming rather than assuming.
- That any Connect Health agent credentials which may have been exposed prior to remediation have been rotated by re-registering the affected agents.
Recommended Actions for CISOs and Organizations
Re-scope your definition of “read-only.”
Inventory every principal holding Global Reader, Security Reader, Security Administrator or Hybrid Identity Administrator, including service principals belonging to compliance scanners, MSSPs and third-party security tooling. Treat each of these as a principal with reach into hybrid identity credential material, not as a safe audit grant. Apply the same lifecycle rigor, conditional access and MFA enforcement you apply to administrative roles.
Rotate agent credentials and monitor for re-registration.
Any AgentKey exposed to a read-only principal should be considered compromised. Re-register affected Connect Health agents, and treat unexplained agent re-registration, or an agent going unexpectedly silent, as a potential indicator rather than routine noise. In this chain, the credential theft and the monitoring outage are the same event.
Build detections for the chain, not just the endpoint.
The observable signals are: calls to Microsoft.ADHybridHealthService/.../credentials from principals that are not performing a genuine server registration; token requests to s1.adhybridhealth.azure.com/oauth2/token originating from cloud infrastructure rather than from your known on-premises agent hosts; and Connect Health agents transitioning to unhealthy or unregistered states with no corresponding change window. Any one of these in isolation is ambiguous. In sequence, they are the attack.
Stop treating monitoring telemetry as reliable.
Connect Health processes AD FS audit events into the Risky IP report and the failed-sign-in and extranet lockout reports that identity and SOC teams use as a detection source. Add validations that offline/mis-configured hosts trigger alerts and responses.