Embedded WebView: NTLM prompt origin transparency and default-on trusted-host enforcement#1856
Embedded WebView: NTLM prompt origin transparency and default-on trusted-host enforcement#1856kaisong1990 with Copilot wants to merge 8 commits into
Conversation
|
@copilot Thanks — the origin-transparency change (showing the host in the prompt) is good. But as written this PR does not close the security finding yet, because host validation is opt-in and never wired up: 1. Make enforcement default-on and request-scoped (replace the global static).
2. Reject untrusted hosts with Cancel, not default handling.
3. Reject sub-resource / non-main-frame NTLM challenges.
4. Hardening details.
5. Tests.
The net behavior should be: out of the box, NTLM prompts only appear for the authority/start-URL host on a main-frame load; everything else is cancelled silently. No caller opt-in should be required to be secure. |
…guard mainFrameHost init
All five points have been addressed:
The auth method property access was also deduplicated into a single |
When an NTLM challenge fires inside the embedded WebView, the credential prompt showed no indication of which host was requesting credentials, and there was no way to restrict prompts to trusted hosts — making the flow vulnerable to UI spoofing from any host loaded in the WebView, including sub-resource loads (img/iframe/XHR) that bypass navigation policy checks entirely.
Changes
Origin transparency
requestingHost:(nullable NSString *)hostto both platformMSIDNTLMUIPromptmethods (iOS + macOS)<host>" so the user always knows which server is requesting credentialsDefault-on, per-request host enforcement (
MSIDOAuth2EmbeddedWebviewController)s_trustedHostsstatic fromMSIDNTLMHandler— it was opt-in, never wired up, and would be clobbered by two concurrent WebView sessions_mainFrameHostivar, seeded automatically fromstartURL.hostat init time (no caller opt-in required)_mainFrameHostis kept current viawebView:decidePolicyForNavigationAction:decisionHandler:— updated only on main-frame navigations (targetFrame.isMainFrame == YES)webView:didReceiveAuthenticationChallenge:completionHandler:whoseprotectionSpace.hostdoes not match_mainFrameHostis immediately cancelled withNSURLSessionAuthChallengeCancelAuthenticationChallenge— no prompt is showncaseInsensitiveCompare:against the SDK constants)Security posture
Out of the box, NTLM/Negotiate prompts appear only for the authority/start-URL host on a main-frame load. All other challenges are silently cancelled. No caller configuration is required to be secure.
Testing
New tests in
MSIDOAuth2EmbeddedWebviewControllerTests:NSURLSessionAuthChallengeCancelAuthenticationChallenge, no promptADFS.Contoso.comvsadfs.contoso.com) → trusted, prompt shownStale tests for the removed global-static allow-list API were removed from
MSIDNTLMHandlerTests.Original prompt
Harden the embedded WebView NTLM credential prompt in IdentityCore: make the requesting host visible to the user and add an optional host allow-list so NTLM credential prompts are not silently shown for arbitrary hosts loaded inside the auth WebView.
Background / Problem
In the embedded WebView authentication flow, when a host loaded inside the WebView issues an NTLM (HTTP Negotiate/NTLM) authentication challenge, IdentityCore unconditionally surfaces a native OS-style credential prompt titled "Enter your credentials" with NO indication of which host is requesting the credentials, and with no host validation anywhere in the dispatch chain. A user in the middle of a trusted sign-in flow cannot tell whether the prompt originates from the legitimate authority or from an attacker-controlled host that the WebView was steered to (open redirect, malicious sub-resource, or a maliciously configured federated/ADFS authority). Credentials entered into that prompt produce an NTLMv2 response that an attacker host can capture. This is a UI-misrepresentation / spoofing weakness (CWE-451) with a secondary improper-authentication aspect (CWE-287).
This is a security hardening change. Frame the PR title/description neutrally as origin-transparency + host allow-list hardening for the NTLM prompt. Do NOT include any attacker proof-of-concept, captured-credential payloads, or step-by-step exploit instructions anywhere in code, comments, commit messages, or the PR body.
Relevant code (paths are relative to repo root)
Trace the chain (do not assume line numbers; locate by symbol):
Required changes
Origin transparency (primary fix — required):
Optional host allow-list hook (defense-in-depth — required, but must be backward compatible):
Feature gating:
Constraints (follow strictly)