This is the technical advisory for VULN-154544. It covers the affected configuration, the decoded tokens, the full endpoint matrix, the root cause, the fix and detection. For how the issue was found and the fourteen-month disclosure, read the research story: Exploiting the Microsoft 365 Substrate. To find and fix the exposure in your own tenant, use the defender companion: Conditional Access Resource Exclusions: Remediation + SIEM.
Abstract
Microsoft Entra ID exempted a set of low-privilege OAuth scopes from any Conditional Access policy that targets All resources and carries a resource exclusion. Microsoft documented the exemption as allowing no data access "beyond basic user profile and group information". This advisory shows that the exemption, combined with Microsoft Graph authorising some first-party public clients on client identity rather than on the token's scp claim, let an attacker holding only a user's password obtain a Microsoft Graph access token with no MFA and no compliant device. With that token the attacker could read the directory, read and write the user's calendar, and query Microsoft Search across mail, Teams chat, OneDrive and SharePoint.
We tested 15 Microsoft first-party public clients against 50 distinct Microsoft Graph requests. Entra ID issued a token to all 15. Six clients were authorised for Graph calls that returned data. Five of them reached data the exempt scopes do not authorise, and reach differed by client even when the tokens carried identical scopes. Microsoft rated the issue Important (Elevation of Privilege) and remediated it service-side through MC1223829, which brings low-privilege scope requests under All resources enforcement.
VULN-154544 in brief
What is VULN-154544? A Conditional Access bypass in Microsoft Entra ID. Where an All resources policy carried a resource exclusion, a username and password alone could obtain a Microsoft Graph token without MFA or a compliant device, and some first-party clients could then read directory data, read and write the user's calendar, and search mail, chat and files with it.
Am I affected? Only if your tenant had an enabled Conditional Access policy that targets All resources and excludes at least one resource, with no other policy enforcing MFA on the same users without exclusions. A tenant in that position was exposed until Microsoft's enforcement change reached it, from 15 June 2026. It is still exposed if Baseline scopes enforcement has been disabled or customised.
Is it fixed? Yes, service-side, through MC1223829. There is no CVE and nothing to install. What is left for defenders is confirming enforcement is on and hunting for historical use (§9).
Advisory summary
- Identifier: VULN-154544 (Microsoft Security Response Centre case)
- CVE: None. Microsoft declined a CVE, citing the Moderate rating it later reversed.
- Vendor: Microsoft
- Affected services: Microsoft Entra ID (Conditional Access evaluation at token issuance). Microsoft Graph v1.0 (delegated authorisation for first-party public clients). Microsoft Search through Microsoft Graph.
- Affected configuration: An enabled Conditional Access policy that targets All resources, applies a grant control such as MFA or a compliant device, and excludes one or more resources.
- Class: Conditional Access policy bypass; authorisation not bound to token scope.
- CWE: CWE-287 Improper Authentication, CWE-285 Improper Authorization, CWE-863 Incorrect Authorization.
- Prerequisites: A valid username and password for a user in scope of the policy. No second factor, no device, no administrative role, no user interaction.
- Impact: Confidentiality: directory objects, the user's calendar, and Microsoft Search results across mail, Teams chat, OneDrive and SharePoint. Integrity: calendar events created and updated as the user, with HTML bodies and attachments delivered to internal and external recipients. Availability: none observed.
- Vendor severity: Important, Elevation of Privilege (initially rated Moderate).
- Remediation: Service-side (MC1223829). Low-privilege scope requests are evaluated as Azure AD Graph, so All resources policies apply. Progressive rollout from 15 June 2026.
- Residual exposure: Tenants that disable or customise Baseline scopes enforcement keep the legacy exemption for the affected policies.
- Reported: 21 May 2025
- Researcher: Rawson Wade, Modern 42 Labs. Initial behaviour observed by Michael Bruce.
1. Background
1.1 Client, resource and where Conditional Access is evaluated
An OAuth 2.0 token request to Entra ID names two things. The client (client_id) is the application making the request. The resource, expressed through scope, is the API that will accept the token and becomes its aud claim. Conditional Access is evaluated when the token is issued, and policy targeting is expressed in terms of the resource.
The client is a request parameter. Public clients hold no secret, so Entra ID does not authenticate them, and the issued token records this as appidacr: 0. Any caller can present any public client's ID.
1.2 The low-privilege scope exemption
When a policy targets All resources and excludes one or more resources, Entra ID did not evaluate that policy for requests that asked only for low-privilege scopes [1]. The exempt set depended on the client type and the API:
- Native and single-page clients, Microsoft Graph:
email,offline_access,openid,profile,User.Read,People.Read - Native and single-page clients, Azure AD Graph:
email,offline_access,openid,profile,User.Read - Confidential clients, Microsoft Graph: the native set, plus
User.Read.All,User.ReadBasic.All,People.Read.All,GroupMember.Read.All,Member.Read.Hidden - Confidential clients, Azure AD Graph: the native set, plus
User.Read.All,User.ReadBasic.All
Two properties of the exemption matter for this advisory:
- It is keyed on the scopes requested, not on the excluded resource. It applies to every client in the tenant, not only to the application the administrator excluded.
- Its safety argument depends on the scopes bounding the token. Microsoft's stated ceiling, basic profile and group information, holds only if the API receiving the token authorises no more than the token's scopes allow.
1.3 Requests for OpenID Connect scopes only
When a v2.0 token request names only OpenID Connect scopes, Entra ID issues an access token for Microsoft Graph, which hosts the UserInfo endpoint [5]. A request for scope=openid therefore yields a token whose aud is Microsoft Graph, even though the caller never named Graph. In our captures, Entra ID also returned more scopes in scp than were requested (§5.2). Every one of them sits inside the exempt set.
1.4 The resource owner password credentials (ROPC) grant and AADSTS50076
The ROPC grant (grant_type=password) exchanges a username and password for tokens with no browser and no interactive step. It cannot satisfy an MFA requirement. Where a policy demands MFA, the token endpoint returns AADSTS50076 instead of a token [4]. A successful ROPC response is therefore direct evidence that no policy required MFA for that request.
ROPC does not support accounts in federated domains (for example AD FS) [4]. The PoC used ROPC only because it needs no browser. The behaviour was first observed with the genuine Teams client signing in interactively, and the exemption is keyed on scope, not on grant type.
1.5 Delegated authorisation: why the scp claim is not exhaustive
For delegated calls, the Microsoft Graph reference documents the permissions each API requires [6], and the token's scp claim lists the delegated permissions granted to the client. Microsoft's access token reference also states that claims such as scp "are not an exhaustive representation of all permissions that a caller may be authorized for" [3]. An API can authorise a caller through mechanisms that leave no trace in the token. That sentence is the hinge of this advisory.
2. Affected configuration and preconditions
The minimal vulnerable configuration is a single policy. The excluded application can be anything. It does not need to be related to the clients used in the attack.
{
"displayName": "Require MFA and compliant device for All resources (one app excluded)",
"state": "enabled",
"conditions": {
"clientAppTypes": ["all"],
"applications": {
"includeApplications": ["All"],
"excludeApplications": ["<any application id>"]
},
"users": { "includeUsers": ["All"] }
},
"grantControls": {
"operator": "AND",
"builtInControls": ["mfa", "compliantDevice"]
}
}Preconditions
- The attacker holds a valid password for a user in scope of the policy. Typical sources are adversary-in-the-middle phishing kits, credential stuffing and infostealer logs.
- At least one enabled policy targets All resources, applies a grant control (MFA, compliant device, or both), and excludes at least one resource.
- No other enabled policy applies a grant or block control to the request. The exemption is evaluated per policy, so a second All resources policy without exclusions would still apply.
- For the ROPC path, the user's domain is managed rather than federated.
Not required: an administrative role, a registered or compliant device, any user interaction, or any consent action. The clients used are Microsoft first-party applications, and no consent prompt was presented or required in testing.
Mitigating factors
- An All resources policy without resource exclusions that requires MFA, or blocks untrusted locations, for the same users.
- Federated authentication, which removes the ROPC path. It does not by itself remove interactive paths.
- Tenants with no resource exclusions on All resources policies were never in scope.
3. Threat model
Attacker. Remote, with knowledge of one user's password and nothing else. The attacker chooses the client_id and scope of the token request, can connect from any network, and uses ordinary HTTP tooling.
Defender intent. The policy author intends that no session reaches anything beyond basic profile and group information without satisfying MFA and device compliance. The exclusion exists for one unrelated application, typically a VPN, an MDM agent or a legacy integration that cannot complete interactive MFA.
Security property violated. A session that has satisfied neither grant control obtained a token, and that token was authorised for directory, calendar and search operations beyond the documented ceiling of the exemption.
4. Method
4.1 Test environment
- A dedicated Entra ID test tenant with one licensed, standard member account. The account held no administrative directory role.
- One enabled Conditional Access policy, as in §2: All users, All resources, one excluded application, grant controls MFA AND compliant device. All other policies were disabled, so results could be attributed to this policy alone.
- Seeded content in the account's mailbox, calendar, OneDrive, SharePoint sites and Teams chats. Seeded items contained a fixed marker string, so search results could be attributed to seeded data.
4.2 Client selection
We shortlisted 15 well-known Microsoft first-party public client IDs (Appendix A). Each was used as client_id in an ROPC request for scope=openid against the tenant's v2.0 token endpoint.
4.3 Harness
For each client that received a token, a PowerShell harness sent a fixed suite of 50 distinct Microsoft Graph v1.0 requests (method and path) with that token. The suite covered user, directory, device, application, role, mail, calendar, contacts, OneDrive, SharePoint, Teams, OneNote, To Do, Bookings, invitation and search operations. It recorded the status code and response body for each request. Write operations used benign test bodies.
The full suite was run twice, on 21 May 2025 and on 30 July 2025. The second run followed MSRC's "by design" response and confirmed the behaviour was unchanged. Three PoC scripts (Teams, Bing Search and Windows Search) were then run against the seeded content and their responses recorded. The access tokens they used were decoded offline.
4.4 Classification and limitations
- Each Graph request is classified as 2xx with data, 2xx with an empty collection, or no 2xx (401, 403 or 400). An empty 2xx proves the call was authorised, not that data would be exposed in a populated tenant.
GET /me/mailreturned 200 for six clients and was listed in the original submission. That path returns the user'smailproperty (their address), not mailbox content, so it is excluded from the results here.- Results come from one tenant, one user and one policy. They describe Microsoft's service behaviour between May and July 2025. Microsoft has since changed that behaviour (§8).
- Search hit counts reflect seeded data and are reported only to show which content types were returned.
5. Technical analysis
The attack has three stages: token issuance without MFA, a token that looks low privilege, and Graph authorisation that does not follow the token's scopes.
5.1 Stage 1: a token from a password alone
The token request, with tenant and user values redacted:
POST /{tenant-id}/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
grant_type=password
&client_id=1fec8e78-bce4-4aaf-ab1b-5451cc387264
&scope=openid
&username={user-principal-name}
&password={password}Expected: AADSTS50076. The user is in scope of a policy requiring MFA and a compliant device, and ROPC can satisfy neither.
Observed: 200 OK with an access token, for all 15 clients tested.
5.2 Stage 2: token anatomy (scp, amr and appidacr: 0)
Decoded claims from the three PoC tokens are shown below, with user, tenant, session and token identifiers omitted.
Claims common to all three tokens:
| Claim | Value |
|---|---|
aud | 00000003-0000-0000-c000-000000000000 (Microsoft Graph) |
appidacr | 0 |
amr | ["pwd"] |
idtyp | user |
ver | 1.0 |
wids | b79fbf4d-3ef9-4689-8143-76b194e85509 |
roles | absent |
| Signature | RS256 |
Claims that differed:
| Claim | Teams | Bing Search | Windows Search |
|---|---|---|---|
appid | 1fec8e78 | cf36b471 | 26a7ee05 |
scp | email openid profile | email openid profile User.Read | email openid profile User.Read |
exp minus iat | 5,515 s | 5,287 s | 5,495 s |
Client IDs are truncated here. Full IDs are in Appendix A.
Reading the claims:
audis Microsoft Graph, although the request named onlyopenid(§1.3).scpis wider than requested but stays inside the exempt set. The Teams token does not carryUser.Read.amrofpwdalone confirms that no second factor was presented.appidacrof0confirms the client was not authenticated. Theappidis whatever the caller supplied.widsholds a single non-administrative role template, consistent with a standard member account.
Nothing in these tokens distinguishes them from a token that legitimately reads one user's own profile.
5.3 Stage 3: Graph authorisation independent of scp
The table below lists, for each call, the least-privileged delegated permission in the Microsoft Graph reference [6] [7]. None of these permissions appeared in the scp of the token that made the call. All paths are under /v1.0.
Clients in this table and in §5.4: TM Microsoft Teams, BS Microsoft Bing Search, BE Bing Search for Microsoft Edge, WS Windows Search, OM Office 365 Management, MD Microsoft Docs.
| Request | Least-privileged permission | Result |
|---|---|---|
GET /me (TM token) | User.Read | 200 |
GET /users | User.ReadBasic.All | 200: TM, BS, BE, OM |
GET /groups | GroupMember.Read.All | 200: TM, BS, BE, OM |
GET /domains | Domain.Read.All | 200: TM, BS, BE |
GET /devices | Device.Read.All | 200: BS, BE |
GET /applications | Application.Read.All | 200: BS, BE |
GET /servicePrincipals | Application.Read.All | 200: BS (PoC run) |
GET /directoryRoles/{id}/members | RoleManagement.Read.Directory | 200: BS, BE |
GET /me/events | Calendars.ReadBasic | 200: TM |
POST /me/events | Calendars.ReadWrite | 201: TM |
POST /me/events/{id}/attachments | Calendars.ReadWrite | 201: TM |
POST /search/query, message | Mail.Read | 200 with hits: WS |
POST /search/query, chatMessage | Chat.Read | 200 with hits: WS |
POST /search/query, driveItem | Files.Read.All | 200 with hits: WS |
Three observations isolate the client as the deciding input:
- A narrower scope set had wider reach. The Teams token lacked
User.Read, yet it read/me, listed users, groups and domains, and created calendar events. - Identical scope sets had disjoint reach. The Bing Search and Windows Search tokens carried the same
scpfor the same user, tenant and policy. Bing Search enumerated devices, applications and role members but could not search. Windows Search could search but could not list users. - Reach resembled each product's function. Teams schedules meetings. Windows Search queries the Microsoft 365 index. The Bing clients serve organisational search over people and resources. The authorisation appears to be provisioned per client for that client's job, then applied to any token presenting that client's ID.
For these clients, Graph's authorisation decision was a function of appid and the user, not of scp.
5.4 Endpoint matrix
Results from both scan runs, aggregated. A cell shows ● if any run returned data. Rows are GET requests to /v1.0 unless marked POST.
Legend: ● 2xx with data. ○ 2xx with an empty collection. × no 2xx (401, 403 or 400). Client codes as in §5.3.
| Request | TM | BS | BE | WS | OM | MD |
|---|---|---|---|---|---|---|
/me | ● | ● | ● | ● | ● | ● |
/me/memberOf | ● | ● | ● | ● | ● | ● |
/me/licenseDetails | ● | ● | ● | ● | ● | ● |
/me/settings | × | ● | × | ● | × | ● |
/me/appRoleAssignments | ○ | ● | ○ | ○ | ● | ● |
/me/sponsors | ○ | ○ | ○ | ○ | ○ | ○ |
/users | ● | ● | ● | × | ● | × |
/groups | ● | ● | ● | × | ● | × |
/domains | ● | ● | ● | × | × | × |
/devices | × | ● | ● | × | × | × |
/devices/{id}/registeredOwners | × | ● | ● | × | × | × |
/devices/{id}/registeredUsers | × | ● | ● | × | × | × |
/applications | × | ● | ● | × | × | × |
/directoryRoles | × | ● | ● | × | × | × |
/directoryRoles/{id}/members | × | ● | ● | × | × | × |
/me/calendars | ● | × | × | × | × | × |
/me/events | ● | × | × | × | × | × |
POST /me/events | ● | × | × | × | × | × |
POST /me/events/{id}/attachments | ● | × | × | × | × | × |
/me/drives | × | ○ | × | ○ | × | ○ |
/me/insights/trending | × | × | × | ○ | × | × |
/sites | ○ | ○ | ○ | ○ | ○ | ○ |
POST /search/query | × | × | × | ● | × | × |
The other nine clients (Appendix A) returned a 2xx only for GET /sites, an empty collection, and × for every other row. For Windows Search, the scan's own search requests returned 200 with zero hits. The ● reflects the PoC run against seeded content in §5.6.
5.5 Requests refused for every client
These requests returned no 2xx response for any of the 15 clients. They show the boundary existed, and they help bound the impact.
| Request | Status |
|---|---|
GET /me/messages, GET /me/mailFolders, POST /me/messages | 401 |
GET /me/contacts, GET /me/people | 401 |
GET /me/drive, POST /me/drive/root/children | 401 |
GET /me/joinedTeams, GET /me/teamwork/associatedTeams | 401 |
GET /me/onenote/notebooks, GET /me/todo/lists | 401 |
GET /me/insights/shared, GET /me/insights/used, GET /me/activities | 401 |
GET /me/cloudClipboard/items, GET /me/permissionGrants | 401 |
GET /solutions/bookingBusinesses and child collections, GET /solutions/bookingCurrencies | 401 |
POST /invitations | 401 |
PATCH /me, PATCH /devices/{id} | 400 (inconclusive) |
The direct mailbox surface (/me/messages, /me/mailFolders) stayed closed, including for Teams, whose calendar surface was open. Mail content was reachable only through Microsoft Search (§5.6). No request could send mail directly. Outbound delivery was possible only as calendar invitations.
5.6 Client capability profiles
Microsoft Teams
Client ID 1fec8e78-bce4-4aaf-ab1b-5451cc387264.
- Directory. Users, groups and domains.
GET /users?$expand=appRoleAssignmentsalso returned 200 in the PoC run, mapping users to their enterprise application assignments. - Calendar read. Calendars and events, including bodies and attendee lists.
- Calendar write.
POST /me/eventswith an HTML body, a meeting location and two attendees outside the tenant returned201 Created, and the invitation was sent from the user's mailbox.POST /me/events/{id}/attachmentswith a file attachment returned201. A follow-upPATCH /me/events/{id}changing the subject returned200.
The write path delivers attacker-controlled HTML and attachments to any internal or external address, as a calendar invitation from a genuine internal sender. The token carried no calendar permission.
Microsoft Bing Search and Bing Search for Microsoft Edge
Client IDs cf36b471-5b44-428c-9ce7-313bf84528de and 2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8. These two clients behaved identically in the scan and gave the broadest directory view:
- Devices, with
isCompliant,isManaged,trustType,operatingSystemVersionandphysicalIds, plus each device's registered owners and users. - Applications, with
identifierUris, redirect URIs acrossweb,spaandpublicClient,requiredResourceAccess, and credential metadata (keyCredentialsandpasswordCredentialskey IDs, hints and validity dates, not the secret values). - Service principals (PoC run): the tenant's full inventory, including
replyUrls,servicePrincipalNames,preferredSingleSignOnMode,samlSingleSignOnSettingsand credential metadata.GET /servicePrincipals?$expand=appRoleAssignedToreturned which users and groups are assigned to each application. - Directory roles and their members, including Global Administrator.
- Groups, including on-premises attributes (
onPremisesSecurityIdentifier,onPremisesSamAccountName,onPremisesDomainName) for synchronised groups, plus users and domains.
Together this is a targeting package: who the administrators are, which devices are unmanaged or non-compliant, which applications use SAML or hold credentials, and who is assigned to them.
Windows Search
Client ID 26a7ee05-5602-4d76-a7ba-eae8b7b67941. Windows Search was the only client authorised for POST /v1.0/search/query, the Microsoft Search API. Results from the PoC run against seeded content:
| Entity type | Normally requires [7] | Hits |
|---|---|---|
message | Mail.Read | 36 |
chatMessage | Chat.Read | 3 |
driveItem | Files.Read.All | 5 |
site | Sites.Read.All | 1 |
event | Calendars.Read | 1 |
person | People.Read | 1 |
Fields returned in the hits:
- Messages:
subject,from,sender,bodyPreview,summary. - Chat messages:
from,summary. - Files (driveItem and listItem resources):
name,webUrl,createdBy,parentReference,summary. - Sites:
name,webUrl,summary. - Events:
subject,summary. - People: the person record.
bodyPreview carries the opening text of each message, and summary carries the indexed text around the matched term. Search results are trimmed to what the user can access, so reach equals the user's own mail, chats, and every file and site shared with them. The attacker chooses the query, so the index can be asked directly for passwords, keys or labelled material rather than crawled.
Office 365 Management and Microsoft Docs
Client IDs 00b41c95-dab0-4487-9791-b9d2c32c80f2 and 18fbca16-2224-45f6-85b0-f7bf2b39b3f3. Office 365 Management listed users and groups. Neither call is authorised by the native exempt scopes. Microsoft Docs reached only the signed-in user's own profile, group memberships, licences and settings. That is consistent with the documented ceiling of the exemption.
Remaining nine clients
The other nine clients received tokens, but no request other than an empty GET /sites returned 2xx. Holding a token was not enough on its own. The reach came from the specific clients above.
6. Root cause analysis
Two independent defects composed into the bypass. Neither alone was a credentials-only path to user data.
6.1 Defect A: the exemption was keyed on what was requested
The exemption decided whether to apply a policy by inspecting the requested scopes. It did not consider which client was asking, or whether that client was the excluded one. Excluding one unrelated application therefore exempted every client's low-privilege requests from that policy. The design was reasonable on one assumption: the token's scopes are the ceiling of what it can do.
6.2 Defect B: authorisation was keyed on an unauthenticated public client ID
For the clients in §5.6, Microsoft Graph authorised requests on the client's identity, through back-end grants that do not appear in scp or roles. For public clients, that identity is the unauthenticated client_id parameter (appidacr: 0). The attacker therefore chose the authorisation input that decided the outcome, while the claim defenders and the exemption relied on (scp) stayed minimal.
6.3 Composition
Defect A's safety depended on scopes bounding the token. Defect B meant scopes did not bound the token for exactly the clients an attacker can impersonate freely. Each layer's guarantee was defined in terms of the other's, and neither held for first-party public clients.
6.4 Vendor-stated root cause
On 7 July 2026 Microsoft attributed the issue to consumer Microsoft Account (MSA) token logic being applied to Entra ID tokens. As we understand it, the consumer model broadly trusts a first-party client to perform its basic function. That is acceptable for consumer accounts, but not for organisational tokens that Conditional Access is meant to gate. It is consistent with the per-client, function-shaped reach observed in §5.3.
7. Impact
- Directory (Bing Search and Bing Search for Microsoft Edge; partially Teams and Office 365 Management): users, groups with on-premises identifiers, domains, devices with compliance and trust state, applications and service principals with SSO configuration and credential metadata, and role assignments including Global Administrator.
- Calendar (Teams): read all events. Create, update and attach files to events, with delivery to internal and external recipients.
- Mail, chat, files and sites (Windows Search): search hits with message previews, chat summaries, file names, locations and text summaries.
- Direct mailbox access: not reachable by any client tested.
- Administrative write operations: not observed.
Boundary of the elevation. No access beyond what the compromised user could reach with a fully consented client was observed. The finding removes the MFA and device-compliance requirement in front of that access. It does not raise the user's own privileges. The elevation crosses the authentication boundary, not the authorisation boundary. That is consistent with Microsoft's final classification of Elevation of Privilege, from password-only attacker to MFA-gated user.
Exploitability. Attack complexity is low. The token request is one HTTP call, the client IDs are public, and the calls are documented Graph APIs. No user interaction is involved, and the sign-in completes as an ordinary single-factor event.
Chained use. Bing-client reconnaissance identifies privileged users and their devices. The Teams write primitive delivers a lure to those users from a trusted internal sender. Windows Search finds credentials and sensitive material in everything the user can see. All three run from the same stolen password with no prompts.
8. Vendor response and remediation
8.1 Assessment history
MSRC first rated the case Moderate (13 June 2025), then described the behaviour as by design (1 July 2025). It confirmed Moderate with no CVE (6 August 2025), and reclassified the case as Important, Elevation of Privilege, in October 2025. The full exchange is told in the research story [12].
8.2 Vendor technical position, and our assessment
MSRC's July 2025 response made three points:
- The low-privilege scope exemption is documented.
- Members can read directory data by default.
- Some first-party applications are authorised through mechanisms that emit no
scporrolesclaim, which the resource API confirms by other means.
On that basis, Microsoft described Conditional Access at token acquisition as "orthogonal to how these apps have permissions granted and what they use for authorization."
Each point is accurate on its own. The finding is their composition. A tenant administrator who configures MFA and a compliant device for All resources has an explicit intent. Microsoft's documentation told that administrator the exemption reached no further than basic profile and group information. In practice, the exemption plus client-keyed authorisation reached calendar write, Microsoft Search and administrator enumeration with a password alone. Microsoft's later reclassification and service-wide enforcement change reflect that reading.
8.3 Fix: MC1223829
Microsoft announced the enforcement change as MC1223829 in January 2026 [9]. It was first scheduled for 27 March 2026, moved to 13 May, then rolled out progressively from 15 June 2026. Low-privilege scope requests are now mapped to Azure AD Graph (00000002-0000-0000-c000-000000000000) for Conditional Access evaluation, so All resources policies apply to them even when the policy has exclusions [2]. Under enforcement, the §5.1 request falls under the MFA requirement, and the ROPC grant fails with AADSTS50076 rather than issuing a token.
Microsoft later added Baseline scopes settings with three modes: enable enforcement (recommended), customise per policy through a dedicated tenant-owned app, or disable enforcement [10]. There is no CVE and no customer-installable patch.
8.4 Residual exposure
- Tenants that disable or customise Baseline scopes enforcement keep the legacy exemption for the affected policies, and with it Stage 1 of this chain.
- Client-keyed authorisation. Microsoft has not published whether Microsoft Graph's authorisation of these first-party clients changed. MC1223829 closes the token-issuance step. A token for one of these clients obtained some other way, such as a stolen refresh token or session, may still carry the client's back-end reach. Shortening how long such a token stays useful is a separate control, covered in Limiting Token Lifetimes in Entra ID.
- Historical exposure. Any tenant that met the §2 preconditions before enforcement reached it was exposed for the life of that configuration. §9 describes how to look back.
9. Detection and hunting
The highest-value question for most tenants is whether this was used before enforcement arrived. Two log sources answer it. Sign-in logs show the single-factor token being issued. Microsoft Graph activity logs [8] show what the token did. Graph activity logs must be exported to a Log Analytics workspace through diagnostic settings, and they cover only the period since export was enabled.
9.1 Sign-in signature
Password-only Microsoft Graph tokens issued through ROPC to the five clients whose reach exceeded the exempt scopes:
// VULN-154544 stage 1: a first-party client with reach beyond the exempt
// scopes obtaining a Microsoft Graph token with a password only, via ROPC.
union SigninLogs, AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(90d)
| where ResultType == "0"
| where AuthenticationProtocol == "ropc"
| where ResourceId == "00000003-0000-0000-c000-000000000000" // Microsoft Graph
| where AppId in (
"1fec8e78-bce4-4aaf-ab1b-5451cc387264", // Microsoft Teams
"cf36b471-5b44-428c-9ce7-313bf84528de", // Microsoft Bing Search
"2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8", // Bing Search for Microsoft Edge
"26a7ee05-5602-4d76-a7ba-eae8b7b67941", // Windows Search
"00b41c95-dab0-4487-9791-b9d2c32c80f2" // Office 365 Management
)
| where AuthenticationRequirement == "singleFactorAuthentication"
| project TimeGenerated, UserPrincipalName, AppDisplayName, AppId, IPAddress,
ConditionalAccessStatus, UserAgent, UniqueTokenIdentifier
| sort by TimeGenerated descRemove the AuthenticationProtocol filter to include interactive sign-ins. That widens the net and adds legitimate noise. The research story's query takes that broader approach across a wider watchlist of first-party clients.
9.2 Scope-to-path mismatch in MicrosoftGraphActivityLogs
The clearest signature is a successful Graph call whose token scopes cannot justify the path:
// VULN-154544: successful Graph calls by the affected clients where the
// token held only exempt scopes but the path needs more.
let ExemptScopes = dynamic(["openid", "profile", "email", "offline_access", "User.Read", "People.Read"]);
MicrosoftGraphActivityLogs
| where TimeGenerated > ago(30d)
| where AppId in (
"1fec8e78-bce4-4aaf-ab1b-5451cc387264", // Microsoft Teams
"cf36b471-5b44-428c-9ce7-313bf84528de", // Microsoft Bing Search
"2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8", // Bing Search for Microsoft Edge
"26a7ee05-5602-4d76-a7ba-eae8b7b67941", // Windows Search
"00b41c95-dab0-4487-9791-b9d2c32c80f2" // Office 365 Management
)
| where ResponseStatusCode between (200 .. 299)
| extend ScopeSet = split(trim(" ", tostring(Scopes)), " ")
| where array_length(set_difference(ScopeSet, ExemptScopes)) == 0
| extend Path = tostring(parse_url(RequestUri).Path)
| where Path matches regex @"^/(v1\.0|beta)/(users|groups|domains|devices|applications|servicePrincipals|directoryRoles|me/events|me/calendars|search/query)"
| summarize Calls = count(),
Paths = make_set(strcat(RequestMethod, " ", Path), 50),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by UserId, AppId, IPAddress, UserAgent
| sort by Calls desc9.3 From sign-in to activity: joining UniqueTokenIdentifier to SignInActivityId
To reconstruct what a specific single-factor token did, join the sign-in's UniqueTokenIdentifier to the Graph log's SignInActivityId:
// VULN-154544: every Graph request made with a single-factor token
// issued to one of the affected clients.
let Stage1 =
union SigninLogs, AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(30d)
| where ResultType == "0"
| where ResourceId == "00000003-0000-0000-c000-000000000000"
| where AppId in (
"1fec8e78-bce4-4aaf-ab1b-5451cc387264",
"cf36b471-5b44-428c-9ce7-313bf84528de",
"2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8",
"26a7ee05-5602-4d76-a7ba-eae8b7b67941",
"00b41c95-dab0-4487-9791-b9d2c32c80f2"
)
| where AuthenticationRequirement == "singleFactorAuthentication"
| project UniqueTokenIdentifier, UserPrincipalName, AppDisplayName, AuthenticationProtocol;
MicrosoftGraphActivityLogs
| where TimeGenerated > ago(30d)
| join kind=inner Stage1 on $left.SignInActivityId == $right.UniqueTokenIdentifier
| extend Path = tostring(parse_url(RequestUri).Path)
| summarize Calls = count(),
Requests = make_set(strcat(RequestMethod, " ", Path, " ", tostring(ResponseStatusCode)), 100)
by UserPrincipalName, AppDisplayName, AuthenticationProtocol, IPAddress
| sort by Calls desc9.4 Indicators
| Indicator | Source | Notes |
|---|---|---|
| ROPC sign-in to Microsoft Graph by Teams, Bing Search, Bing Search for Microsoft Edge or Windows Search | Interactive sign-in logs | The genuine apps sign in through a browser or an authentication broker, so ROPC from these client IDs is unusual |
| Single-factor token for one of these clients while the same user's other sessions satisfy MFA | Interactive and non-interactive sign-in logs | Compare AuthenticationRequirement across the user's sign-ins |
Successful calls with exempt-only Scopes against directory, calendar or search paths | Graph activity logs | §9.2 |
POST /me/events or POST /me/events/{id}/attachments from the Teams client ID shortly after a single-factor sign-in | Graph activity logs | Calendar lure delivery |
POST /search/query from the Windows Search client ID with a non-Windows user agent | Graph activity logs | User agents are attacker-controlled. Treat as supporting evidence only. |
For scope extraction from AuthenticationProcessingDetails, Splunk SPL versions, and a PowerShell audit of which service principals hold the exempt grants, see the defender companion [13].
10. Recommendations
- Keep Baseline scopes enforcement on. If it is set to customise or disable, treat every affected policy as exposed to §5.1, and set a date to return to enforcement [10].
- Build a baseline MFA policy with no resource exclusions. Target all users and all resources, with user exclusions only for break-glass accounts [11]. This closes the whole class, not only this instance.
- Audit every resource exclusion on All resources policies. Remove exclusions whose original reason no longer holds, rather than working around them. The SuiteAuth toolkit reproduces the token requests in this advisory against your own policies, and a Conditional Access review covers the exclusions alongside the rest of the policy set.
- Export Microsoft Graph activity logs to your SIEM and keep them long enough to hunt (§9). Without them you can see that a single-factor token was issued, but not what it did.
- Run the §9 queries over as much history as you hold. Pay particular attention to the period before enforcement reached your tenant.
- Do not infer a token's capability from
scpin your own tooling or threat models, especially for first-party public clients. The claim is documented as non-exhaustive [3], and this advisory shows by how much.
11. Discussion
Token claims are evidence, not authority. Defenders, auditors and policy engines reason about tokens through their claims. VULN-154544 shows a resource making authorisation decisions the token does not express. Any control that reasons only about claims, such as the exemption in §1.2, inherits that blind spot.
A public client ID is not an identity. appidacr: 0 means the token endpoint did not authenticate the client. Using an unauthenticated client_id as an authorisation input lets an attacker choose their own privileges from a menu of first-party clients.
Exemptions should bind to what is granted, not to what is asked. An exemption keyed on requested scopes is safe only if the receiving API honours those scopes as a ceiling. In our view, safer designs bind an exemption to the excluded resource itself, or refuse back-end grants the token does not carry. MC1223829 takes the first route by bringing these requests back under policy.
Configuration that looks reasonable is the attack surface. Every precondition here is ordinary: one stolen password and one legitimate exclusion. The defect lived in how two documented behaviours interacted. That is why it survived review, and why it was hard to communicate as a vulnerability rather than a feature.
12. Disclosure timeline
| Date | Event |
|---|---|
| 21 May 2025 | Reported to MSRC with PoC scripts for three clients and the endpoint scan |
| 13 Jun 2025 | Rated Moderate |
| 1 Jul 2025 | MSRC described the behaviour as by design |
| 30 Jul 2025 | Second full scan run. Behaviour unchanged. |
| 6 Aug 2025 | Moderate confirmed. No CVE to be issued. |
| 10 to 15 Oct 2025 | MSRC reviewed conference material, reclassified the case as Important and confirmed bounty eligibility |
| 16 Oct 2025 | Conference talk delivered with technical detail redacted |
| 17 Oct 2025 | Bounty awarded. Case recorded as Important, Elevation of Privilege. |
| Jan 2026 | Microsoft announced MC1223829 |
| 15 Jun 2026 | Enforcement began rolling out progressively, after moving from 27 March and 13 May 2026 |
| 7 Jul 2026 | Microsoft shared the root cause |
| 27 Jul 2026 | Microsoft invited a full public presentation of the finding |
| 22 Oct 2026 | Research story published |
| 10 Nov 2026 | This advisory published |
13. References
- Microsoft Learn, Targeting resources in Conditional Access policies, section on the behaviour of All resources policies with an app exclusion.
- Microsoft Learn, Conditional Access enforcement for policies with resource exclusions.
- Microsoft Learn, Access token claims reference.
- Microsoft Learn, Microsoft identity platform and OAuth 2.0 Resource Owner Password Credentials.
- Microsoft Learn, Microsoft identity platform UserInfo endpoint.
- Microsoft Learn, Microsoft Graph permissions reference, and the permissions section of each API page cited in §5.3.
- Microsoft Learn, Use the Microsoft Search API to query data.
- Microsoft Learn, Access Microsoft Graph activity logs.
- Microsoft Entra Blog, Upcoming changes to Conditional Access enforcement for resource exclusions.
- Microsoft, Baseline scopes settings guidance.
- Microsoft Learn, Require multifactor authentication for all users with Conditional Access.
- Modern 42, Exploiting the Microsoft 365 Substrate: How First-Party OAuth Clients Became an MFA Bypass, the research story and disclosure narrative.
- Modern 42, Conditional Access Resource Exclusions: Remediation + SIEM, the defender companion.
Related Modern 42 Labs research on Conditional Access controls that did not hold: VULN-172966: Satisfying App Protection Conditional Access With a Self-Attested MAM Enrolment and Your Conditional Access Device Filters Are a Paper Wall. Both are listed with this one in the Labs disclosure register.
Appendix A: First-party public clients tested
| Application | Application ID | Reach beyond the user's own profile |
|---|---|---|
| Microsoft Teams | 1fec8e78-bce4-4aaf-ab1b-5451cc387264 | Directory, calendar read and write |
| Microsoft Bing Search | cf36b471-5b44-428c-9ce7-313bf84528de | Directory including devices, applications and roles |
| Bing Search for Microsoft Edge | 2d7f3606-b07d-41d1-b9d2-0d0c9296a6e8 | Directory including devices, applications and roles |
| Windows Search | 26a7ee05-5602-4d76-a7ba-eae8b7b67941 | Microsoft Search |
| Office 365 Management | 00b41c95-dab0-4487-9791-b9d2c32c80f2 | Users and groups |
| Microsoft Docs | 18fbca16-2224-45f6-85b0-f7bf2b39b3f3 | None |
| Windows Spotlight | 1b3c667f-cde3-4090-b60b-3d2abd0117f0 | None |
| Enterprise Roaming and Backup | 60c8bde5-3167-4f92-8fdb-059f6176dc0f | None |
| Microsoft Azure CLI | 04b07795-8ddb-461a-bbee-02f9e1bf7b46 | None |
| Microsoft Azure PowerShell | 1950a258-227b-4e31-a9cf-717495945fc2 | None |
| Microsoft Exchange REST API Based PowerShell | fb78d390-0c51-40cd-8e17-fdbfab77341b | None |
| Microsoft Intune Windows Agent | fc0f3af4-6835-4174-b806-f7db311fd2f3 | None |
| Microsoft Outlook | 5d661950-3475-41cd-a2c3-d671a3162bc1 | None |
| Outlook Mobile | 27922004-5251-4030-b22d-91ecd9a37ea4 | None |
| Universal Store Native Client | 268761a2-03f3-40df-8a8b-c3db24145b6b | None |
"None" means no 2xx response beyond an empty collection, in the configuration tested.
Appendix B: Evidence handling
- The tests in this advisory ran against a dedicated test tenant and a test account created for this research.
- Tenant IDs, user principal names, object IDs, device IDs, directory role object IDs, event IDs and token values are redacted throughout. Client IDs are Microsoft's public first-party identifiers.
- Write tests used benign content. Test attachments contained a fixed text string, not executable code.
- Request bodies for Graph calls are described rather than reproduced. The calls are standard, documented Microsoft Graph operations.
Credits
Research, proof of concept and disclosure by Rawson Wade, Modern 42 Labs. The initial behaviour was observed by Michael Bruce during a Modern 42 Conditional Access assessment.
If you want a hand pressure-testing your own Entra ID posture, book a 30-min discussion with one of our engineers.

