Conversation
bgavrilMS
reviewed
Feb 19, 2026
src/client/Microsoft.Identity.Client/ManagedIdentity/V2/ImdsV2ManagedIdentitySource.cs
Show resolved
Hide resolved
bgavrilMS
reviewed
Feb 19, 2026
src/client/Microsoft.Identity.Client/ManagedIdentity/V2/MtlsCertificateCache.cs
Show resolved
Hide resolved
bgavrilMS
reviewed
Feb 19, 2026
src/client/Microsoft.Identity.Client/ManagedIdentity/V2/IPersistentCertificateCache.cs
Show resolved
Hide resolved
bgavrilMS
reviewed
Feb 19, 2026
src/client/Microsoft.Identity.Client/ManagedIdentity/V2/WindowsPersistentCertificateCache.cs
Outdated
Show resolved
Hide resolved
bgavrilMS
approved these changes
Feb 19, 2026
trwalke
reviewed
Feb 23, 2026
src/client/Microsoft.Identity.Client/ManagedIdentity/V2/MtlsCertificateCache.cs
Show resolved
Hide resolved
trwalke
approved these changes
Feb 23, 2026
….com/AzureAD/microsoft-authentication-library-for-dotnet into gladjohn/fix-mtls-handshake-failures
trwalke
approved these changes
Feb 24, 2026
This was referenced Mar 9, 2026
This was referenced Mar 16, 2026
chore(deps): Bump Azure.Identity and Microsoft.Identity.Client
LaurentAerens/rsd-clamav-api-azure#53
Merged
Closed
This was referenced Mar 23, 2026
This was referenced Mar 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5755
PR Title
IMDSv2 mTLS: Auto-recover from SCHANNEL handshake failures by evicting
cached cert and re-minting
Summary
This PR fixes an intermittent but persistent failure in the IMDSv2 mTLS
PoP flow on Windows where MSAL reuses a cached/persisted mTLS binding
certificate whose private key becomes unusable (e.g., corrupted,
inaccessible, or otherwise rejected by SCHANNEL).
When this occurs, the TLS handshake fails and the token request
consistently errors until the bad certificate is manually removed from
the persistent store.
The fix introduces self-healing behavior: when we detect a
SCHANNEL-style failure during the token request, we remove the cached
mTLS binding (both in-memory and persisted store) and retry once. This
forces minting a fresh certificate/key binding and restores normal
operation.
Problem / Issue Description
In the IMDSv2 mTLS PoP flow, MSAL caches the mTLS binding (certificate +
endpoint + canonical
client_id) in:CurrentUser\My) viaFriendlyNametaggingIn rare cases, the persisted certificate entry can appear valid (e.g.,
HasPrivateKey == true, unexpired) but still fail during TLS handshakedue to SCHANNEL rejecting the client credential.
This typically manifests as a transport-layer failure during the token
request:
Wrapped as:
Because the cached binding is reused on subsequent requests, the failure
becomes sticky: every token acquisition attempt reuses the same bad
certificate and fails repeatedly until the certificate is manually
removed from the store.
Root Cause
The persistent cache selection logic previously treated a certificate as
usable if it:
FriendlyNameHasPrivateKey == trueHowever, on Windows this is not sufficient.
HasPrivateKeydoes not guarantee the private key is actuallyusable by SCHANNEL. The private key can be:
When SCHANNEL attempts the client-auth signature, the connection is
reset and the HTTP request fails.
Static validation cannot reliably predict this failure.
Fix
1) Detect SCHANNEL-style mTLS handshake failures
In
ImdsV2ManagedIdentitySource.AuthenticateAsync, catchMsalServiceExceptionwhere:ErrorCode == managed_identity_unreachable_network(e.g.,
SocketException 10054, "forcibly closed by the remotehost")
2) Evict the bad binding from caches
Remove the binding from:
3) Retry once
Immediately retry
base.AuthenticateAsync(...).Since the cached entry was removed, the flow re-mints a fresh
certificate and proceeds successfully.
Retry is strictly limited to one attempt.
Key Code Changes
ImdsV2ManagedIdentitySourceMtlsBindingCacheRemoveBadCert(cacheKey, logger)to remove from:WindowsPersistentCertificateCacheDeleteAllForAlias(alias, logger)Deletes all tagged certs for the alias (not just expired ones),
enabling a full reset of a corrupted binding set.
Behavioral Impact
✅ No change for normal success paths.
✅ When SCHANNEL rejects a cached certificate, the system recovers
automatically without manual cleanup.
✅ Cache eviction is scoped to the affected alias (including attestation
tag), so unrelated bindings are not impacted.
failures or causing repeated mint loops.
Example Failure This Fix Addresses
Typical failure:
Inner exceptions:
After this PR:
Testing
unit tests have been added