Skip to content

Fix HybridWebView message handling across platforms - #38078

Merged
kubaflo merged 4 commits into
inflight/currentfrom
mattleibow-hybridwebview-message-origin
Sep 2, 2026
Merged

kubaflo merged 4 commits into
inflight/currentfrom
mattleibow-hybridwebview-message-origin

Conversation

@mattleibow

@mattleibow mattleibow commented Sep 1, 2026 •

Copy link
Copy Markdown
Member

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Root Cause

HybridWebView uses platform-specific mechanisms to receive messages from its hosted content. The Windows and Apple callbacks exposed the sender location, but that value was not used when forwarding messages to the shared handler:

  • Windows forwarded CoreWebView2WebMessageReceivedEventArgs payloads without checking Source.
  • iOS and Mac Catalyst substituted AppOriginUri instead of using the URL from WKScriptMessage.FrameInfo.

As a result, message processing remained active when the same control displayed content outside the app content URI.

Description of Change

This change validates the sender before dispatching incoming messages:

  • Windows: parses CoreWebView2WebMessageReceivedEventArgs.Source and continues only when it is within AppOriginUri.
  • iOS and Mac Catalyst: passes WKScriptMessage.FrameInfo.Request.Url into the message path and applies the same AppOriginUri.IsBaseOf(...) check.
  • Android: keeps the existing runtime implementation. Android already routes page-to-.NET messages through the app URI endpoint and validates the request location before dispatching.

Messages with a missing, malformed, or different source URI are ignored. The source URL is not included in diagnostic output.

The implementation intentionally uses the existing Uri.TryCreate(...) and AppOriginUri.IsBaseOf(...) pattern rather than adding another URI comparison helper. This matches the existing WebView message and resource-routing code.

Compatibility

  • No public API changes.
  • No new dependencies.
  • Messages from packaged app content continue through the existing shared parser.
  • Android behavior is unchanged.
  • Content outside the app URI can still be displayed; only its messages are excluded from the app message path.

Regression Coverage

Added Controls device tests that replace the packaged page with deterministic HTML at a different origin in the same HybridWebView. The tests verify that:

  • RawMessageReceived is not raised for a raw message from that document.
  • A JavaScript completion message from that document does not complete a pending invocation task.
  • The replacement document finished loading before either assertion, so a navigation failure cannot make the test pass.

The test content is provided locally:

  • Windows and Android return the HTML through WebResourceRequested.
  • iOS and Mac Catalyst load the HTML with a separate base URL.
  • Android additionally verifies that the app URI endpoint was attempted before asserting that no message was dispatched.

No external network service is required by these tests.

Validation

  • Fail-before check: both new tests fail without the Windows/Apple handler changes and pass with them.
  • Mac Catalyst: 97 tests run, 96 passed, 0 failed, 1 existing skip.
  • iOS: 97 tests run, 96 passed, 0 failed, 1 existing skip.
  • Android: 100 tests run, 95 passed, 0 failed, 5 existing skips.
  • Windows: Windows-specific regression coverage is included; runtime execution was not available on the current macOS host.

Issues Fixed

N/A

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 38078

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 38078"

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

@mattleibow

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Sep 1, 2026

@MauiBot MauiBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Review Summary

@mattleibow — new AI review results are available based on commit 5f53308.

Gate Inconclusive Confidence Low Platform iOS


🗂️ Review Sessions — click to expand
🚦 Gate — Test Before & After Fix

Gate Result: ⚠️ INCONCLUSIVE

Platform: IOS · Base: main · Merge base: d2edf197

🩺 Could not verify — environment/infrastructure error. The gate ran the tests but hit an environment error (an emulator/simulator/Appium/XHarness flake, a device that would not boot, or an empty/invalid result file), so it could not record a real pass/fail. The ⚠️ ENV ERROR marks below are infrastructure, not test failures — this is not a problem with your PR. Comment /review to retry on a fresh agent.

XHarness did not produce the expected fresh result 'testResults.xml' for requested class(es) 'Microsoft.Maui.DeviceTests.HybridWebViewTests_MessageOrigins' (the target tests did not run).

Test Without Fix (expect FAIL) With Fix (expect PASS)
📱 HybridWebViewTests_MessageOrigins (RawMessagesFromOtherOriginsAreIgnored, InvokeCompletionsFromOtherOriginsAreIgnored) Category=HybridWebView ⚠️ ENV ERROR ⚠️ ENV ERROR
🔴 Without fix — 📱 HybridWebViewTests_MessageOrigins (RawMessagesFromOtherOriginsAreIgnored, InvokeCompletionsFromOtherOriginsAreIgnored): ⚠️ ENV ERROR · 250s

No log file found

🟢 With fix — 📱 HybridWebViewTests_MessageOrigins (RawMessagesFromOtherOriginsAreIgnored, InvokeCompletionsFromOtherOriginsAreIgnored): ⚠️ ENV ERROR · 83s

No log file found

⚠️ Failure Details

  • ⚠️ HybridWebViewTests_MessageOrigins (RawMessagesFromOtherOriginsAreIgnored, InvokeCompletionsFromOtherOriginsAreIgnored) without fix: XHarness did not produce the expected fresh result 'testResults.xml' for requested class(es) 'Microsoft.Maui.DeviceTests.HybridWebViewTests_MessageOrigins' (the target tests did not run).
  • ⚠️ HybridWebViewTests_MessageOrigins (RawMessagesFromOtherOriginsAreIgnored, InvokeCompletionsFromOtherOriginsAreIgnored) with fix: XHarness did not produce the expected fresh result 'testResults.xml' for requested class(es) 'Microsoft.Maui.DeviceTests.HybridWebViewTests_MessageOrigins' (the target tests did not run).
📁 Fix files reverted (2 files)
  • src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Windows.cs
  • src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.iOS.cs

📋 Pre-Flight — Context & Validation

PR #38078 Pre-Flight

Context

  • Title: Fix HybridWebView message handling across platforms
  • Base: main (d2edf1972d09f6689a4621ba9ff42346ced6f1b1)
  • Materialized review commit: 7c043d17bbfd3219e7b4be90639c479f85abbd83
  • PR head: 5f53308d21e85d512e1741a951918dcd7e407633
  • Linked issue: None
  • Test platform: iOS

Problem

HybridWebView accepts messages from hosted web content through platform-native callbacks. Before this PR, the Windows callback forwarded a message without validating CoreWebView2WebMessageReceivedEventArgs.Source, while the Apple callback discarded the real sender URL and passed AppOriginUri to the shared message path. A document loaded from another origin could therefore deliver raw messages or forged JavaScript-invocation completions to the app.

Existing PR Approach

  • HybridWebViewHandler.iOS.cs passes WKScriptMessage.FrameInfo.Request.Url?.AbsoluteString into a source-aware overload, parses it as an absolute Uri, and accepts it only when AppOriginUri.IsBaseOf(sourceUri).
  • HybridWebViewHandler.Windows.cs applies the equivalent Uri.TryCreate and AppOriginUri.IsBaseOf check to CoreWebView2WebMessageReceivedEventArgs.Source.
  • Missing, malformed, and non-app origins are logged without including source data, then ignored.
  • Four new platform-partial test files exercise deterministic other-origin documents without external network access.

Direct Diff Inspection

The PR changes six files: four added Controls device-test files plus the existing iOS and Windows HybridWebViewHandler implementations. Production changes are limited to:

  • src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.iOS.cs
  • src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Windows.cs

The alternative attempts may inspect all six files, but the baseline script's modification allow-list is expected to contain only the two existing production files above. Each attempt must verify .github/.baseline-state.json and obey its actual RevertedFiles/NewFiles values.

Bounded Validation

The detected primary test is the new Controls device-test class containing:

  • RawMessagesFromOtherOriginsAreIgnored
  • InvokeCompletionsFromOtherOriginsAreIgnored

Run only:

pwsh .github/skills/run-device-tests/scripts/Run-DeviceTests.ps1 -Project Controls -Platform ios -TestFilter "Category=HybridWebView" -IncludeClasses "Microsoft.Maui.DeviceTests.HybridWebViewTests_MessageOrigins"

No mandatory regression tests were supplied in the STEP 5a request, so no additional test suite or category may be run.

Existing Evidence and Constraints

  • The prior gate is INCONCLUSIVE because its result-file freshness check did not find the expected testResults.xml; it must not be rerun or treated as a code failure.
  • The gate's retained XHarness diagnostics contain two failing target tests without the PR fix and two passing target tests with it, but the authoritative gate verdict remains inconclusive.
  • The worktree contains extensive pre-existing review-harness changes outside the PR commit. They are not part of candidate work and must remain untouched.
  • Each candidate gets one implementation/test pass and at most one focused correction/retest, followed by the exact restore command required by the try-fix skill.

🔬 Code Review — Deep Analysis

Expert Code Review — PR #38078

Verdict

LGTM on code merits
Confidence: low

The submitted fix is technically sound on code inspection, and the expert reviewer found no actionable file:line defects. The generic review policy would normally withhold LGTM when required-check status is unknown, but this run's explicit trusted-Gate contract classifies INCONCLUSIVE as non-failing and prohibits requesting changes solely for that environment result. The low confidence records that evidence limitation without converting it into a code objection.

Independent Assessment

The Windows and Apple HybridWebView handlers now authorize inbound messages using the native callback's sender URL before forwarding the payload to shared dispatch. Windows validates CoreWebView2WebMessageReceivedEventArgs.Source; iOS and Mac Catalyst forward WKScriptMessage.FrameInfo.Request.Url?.AbsoluteString to a source-aware message path. Both use absolute Uri.TryCreate(...) parsing plus AppOriginUri.IsBaseOf(...), and ignore missing, malformed, or non-app sources.

The four new device-test files replace packaged content with deterministic content from another origin and cover both raw messages and forged JavaScript invocation completions. The implementation is localized to per-message handler plumbing, introduces no public API, dependency, static state, subscription, or startup-path change, and follows the repository's existing URI-validation pattern.

Findings

No actionable findings were validated on added or modified lines. The required inline-findings.json contains an empty JSON array.

Failure-Mode Probing

  • Missing or malformed callback source: Uri.TryCreate fails and the message is dropped before shared dispatch.
  • Different-origin top-level content: AppOriginUri.IsBaseOf(sourceUri) is false and neither raw-message nor invocation-completion handling runs.
  • Packaged app content: its source remains under AppOriginUri, so the existing shared parser still receives the message.
  • Handler disconnect/reconnect: the guard is stateless and adds no event subscriptions or lifecycle state that can accumulate.
  • Startup and unrelated controls: the new logic runs only when a HybridWebView native message callback fires; it does not affect initialization.

Narrative and Prior-Review Reconciliation

The code-first assessment agrees with the PR narrative's root cause, platform behavior, Android non-change, compatibility claims, and stated regression scope. Review of top-level reviews, inline comments, and issue comments found no prior error-level findings requiring reconciliation.

Validation Evidence

The trusted Gate is INCONCLUSIVE because its build/run result could not be established. Per the supplied contract, this is not treated as a regression failure and the Gate was not rerun. Platform-specific handler plumbing and absent authoritative test execution cap confidence at low.


🛠️ Try-Fix — Analysis & Comparison

STEP 5a Alternative Fix Candidates

Candidate 1 — Provenance-Bound Main-Frame Validation (gpt-5.3-codex)

Approach: Authorize a message by native main-frame identity and an exact match to the active top-level document URL rather than trusting any URL for which AppOriginUri.IsBaseOf(...) returns true.

Current approach avoided: PR #38078 parses the callback-provided source URL and accepts it when it is under AppOriginUri. This candidate instead proposed binding authorization to the active main document and, on Apple, the callback's main-frame provenance.

Mechanism-level difference: The PR treats origin membership as sufficient proof. The candidate would require the message to come from the currently displayed top-level document, preventing a same-origin subframe or stale navigation callback from being treated as the active app document merely because its URL shares the app URI prefix.

Result: ⚠️ Blocked before editing

EstablishBrokenBaseline.ps1 rejected the pre-existing dirty review-harness worktree with DIRTY WORKING DIRECTORY. Because .github/.baseline-state.json was not created, the skill's modification boundary could not be established. No production or test file was changed and the required iOS test was not run.

Candidate diff: Empty.

Self-review: 0 findings (reviewer-findings.json contains []).

Restore: The exact required command ran and reported No baseline state found / Restored False, which is the expected no-state result for this pre-edit block.

Detailed artifacts: CustomAgentLogsTmp/PRState/38078/PRAgent/try-fix-1/content.md and CustomAgentLogsTmp/PRState/38078/PRAgent/try-fix/attempt-1/.

Candidate 2 — Authenticated Bridge Envelope (gpt-5.6-sol)

Approach: Provision a per-handler unguessable capability through the trusted bridge bootstrap and require every native-to-.NET bridge envelope to present that capability before dispatch.

Approaches avoided: This does not use the PR's callback-source parsing and AppOriginUri.IsBaseOf(...) authorization. It also does not repeat candidate 1's main-frame identity and current-document URL matching.

Mechanism-level difference: The PR and candidate 1 authorize sender-location metadata. This candidate would authenticate the message payload itself: only JavaScript initialized by MAUI's trusted bootstrap receives the per-handler capability, so another-origin content cannot create an accepted raw-message or invocation-completion envelope merely by gaining access to a native bridge API or presenting a plausible URL.

Result: ⚠️ Blocked before editing

EstablishBrokenBaseline.ps1 again rejected the pre-existing dirty review-harness worktree and did not create .github/.baseline-state.json. The required modification allow-list was therefore unavailable. No production or test file was changed and the required iOS test was not run.

Candidate diff: Empty.

Self-review: 0 findings (reviewer-findings.json contains []).

Restore: The exact required command ran and reported No baseline state found / Restored False, the expected no-state result for this pre-edit block.

Detailed artifacts: CustomAgentLogsTmp/PRState/38078/PRAgent/try-fix-2/content.md and CustomAgentLogsTmp/PRState/38078/PRAgent/try-fix/attempt-2/.

Aggregate Outcome

Two mechanism-level alternatives were bounded and recorded. Neither could be implemented or tested because the mandatory baseline script refused the pre-existing dirty harness worktree before producing its file modification allow-list. The PR's existing fix remains unverified by STEP 5a; the separate gate verdict remains INCONCLUSIVE and was not rerun or altered.


📝 PR Finalize — Recommended Title & Description

Assessment: ✏️ Recommend updating — the description is accurate and complete, but the title is vague and omits both the affected-platform prefix and the sender-origin behavior.

Recommended title

[Windows/iOS/Mac Catalyst] HybridWebView: Reject messages outside the app origin

Recommended description

### Root Cause

`HybridWebView` uses platform-specific mechanisms to receive messages from its hosted content. The Windows and Apple callbacks exposed the sender location, but that value was not used when forwarding messages to the shared handler:

- Windows forwarded `CoreWebView2WebMessageReceivedEventArgs` payloads without checking `Source`.
- iOS and Mac Catalyst substituted `AppOriginUri` instead of using the URL from `WKScriptMessage.FrameInfo`.

As a result, message processing remained active when the same control displayed content outside the app content URI.

### Description of Change

This change validates the sender before dispatching incoming messages:

- **Windows:** parses `CoreWebView2WebMessageReceivedEventArgs.Source` and continues only when it is within `AppOriginUri`.
- **iOS and Mac Catalyst:** passes `WKScriptMessage.FrameInfo.Request.Url` into the message path and applies the same `AppOriginUri.IsBaseOf(...)` check.
- **Android:** keeps the existing runtime implementation. Android already routes page-to-.NET messages through the app URI endpoint and validates the request location before dispatching.

Messages with a missing, malformed, or different source URI are ignored. The source URL is not included in diagnostic output.

The implementation intentionally uses the existing `Uri.TryCreate(...)` and `AppOriginUri.IsBaseOf(...)` pattern rather than adding another URI comparison helper. This matches the existing WebView message and resource-routing code.

### Compatibility

- No public API changes.
- No new dependencies.
- Messages from packaged app content continue through the existing shared parser.
- Android behavior is unchanged.
- Content outside the app URI can still be displayed; only its messages are excluded from the app message path.

### Regression Coverage

Added Controls device tests that replace the packaged page with deterministic HTML at a different origin in the same `HybridWebView`. The tests verify that:

- `RawMessageReceived` is not raised for a raw message from that document.
- A JavaScript completion message from that document does not complete a pending invocation task.
- The replacement document finished loading before either assertion, so a navigation failure cannot make the test pass.

The test content is provided locally:

- Windows and Android return the HTML through `WebResourceRequested`.
- iOS and Mac Catalyst load the HTML with a separate base URL.
- Android additionally verifies that the app URI endpoint was attempted before asserting that no message was dispatched.

No external network service is required by these tests.

### Validation

- **Fail-before check:** both new tests fail without the Windows/Apple handler changes and pass with them.
- **Mac Catalyst:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **iOS:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **Android:** 100 tests run, 95 passed, 0 failed, 5 existing skips.
- **Windows:** Windows-specific regression coverage is included; runtime execution was not available on the current macOS host.

### Issues Fixed

N/A

🏁 Report — Final Recommendation

✅ Final Recommendation: APPROVE

Winning Candidate

Winner: pr

The raw PR is the only distinct, implemented fix. Its Windows and Apple source checks directly close the demonstrated message-dispatch gap, its device tests cover both exposed message paths, and the single expert review found no actionable error, warning, lifecycle issue, or unresolved prior-review finding. The trusted Gate is INCONCLUSIVE, not failed; under the supplied contract this environment result is non-blocking and is recorded as uncertainty rather than converted into a request for code changes.

Comparative Ranking

Rank Candidate Implementation Regression evidence Expert assessment Decision
1 pr Complete Windows and iOS/Mac Catalyst sender validation plus targeted cross-platform device tests Trusted Gate INCONCLUSIVE because no fresh XHarness result was produced; no regression failure established. Mechanical regression cross-reference is CLEAN. No actionable findings; sound, localized use of the existing absolute-URI and AppOriginUri.IsBaseOf(...) pattern. Wins on correctness, completeness, and lowest change risk.
2 pr-plus-reviewer Identical to pr; expert feedback required no patch (reviewer.patch is empty) No separate validation was warranted because there was no reviewer delta; it inherits the raw PR's inconclusive evidence. No improvement over the submitted code. Ranked below pr because it is not a distinct stronger candidate.
3 try-fix-1 Concept only: main-frame identity plus exact active-document URL matching. Blocked before editing; candidate diff is empty. Required iOS command not run; no pass or failure. Could narrow accepted provenance, but has no implementation evidence and may reject legitimate same-origin frame scenarios more aggressively than required. Cannot outrank a complete, review-clean fix.
4 try-fix-2 Concept only: per-handler authenticated bridge envelope. Blocked before editing; candidate diff is empty. Required iOS command not run; no pass or failure. Substantially broadens protocol/state complexity without implementation, compatibility, or lifecycle evidence. Highest uncertainty and unnecessary scope relative to the localized fix.

No candidate recorded a regression-test failure, and no candidate recorded an authoritative regression-test pass. The mandatory rule to rank failed candidates below passing candidates therefore does not alter the ordering.

Why the PR Approach Wins

  • It uses sender metadata already supplied by WKScriptMessage.FrameInfo.Request.Url and CoreWebView2WebMessageReceivedEventArgs.Source, avoiding new state or transport protocol.
  • Missing, malformed, and other-origin values are rejected before either raw-message dispatch or invocation-task completion.
  • The change is per-callback and stateless: no startup work, static state, subscription, or reconnect behavior is introduced.
  • The tests first establish that the replacement document loaded, avoiding a false pass caused by failed navigation.
  • Android production behavior remains unchanged while the shared tests exercise its existing request-location guard.

Residual Uncertainty

The focused iOS Gate did not yield authoritative test results because the expected result file was absent. This limits empirical confidence, but it is an infrastructure/build-result gap rather than evidence that the fix or tests failed. No additional Gate run was performed.


📱 UI Tests — ViewBaseTests,WebView

Detected UI test categories: ViewBaseTests,WebView

✅ Deep UI tests — 162 passed, 0 failed, 1 skipped across 2 categories on platform-pool agent (replaces in-process counts above).

🧪 UI Test Execution Results (deep, platform pool)

Category Tests Snapshot diffs
ViewBaseTests 112/112 ✓ —
WebView 50/51 (1 skipped) ✓ —
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs)

🧭 Next Steps — review latest findings

No alternative fix was selected for this run. Review the session findings and CI results before merging.

@MauiBot MauiBot added s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review) and removed s/agent-review-in-progress AI review is currently running for this PR labels Sep 1, 2026
@mattleibow
mattleibow marked this pull request as ready for review September 1, 2026 21:35
Copilot AI lite review requested due to automatic review settings September 1, 2026 21:35
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR tightens HybridWebView message dispatch so only messages originating from the app’s internal content origin (AppOriginUri) are forwarded into the shared message parser, preventing cross-origin content hosted in the same control from invoking the app message bridge.

Changes:

  • Windows: validate CoreWebView2WebMessageReceivedEventArgs.Source is within AppOriginUri before dispatching messages.
  • iOS/MacCatalyst: validate WKScriptMessage.FrameInfo.Request.Url is within AppOriginUri before dispatching messages.
  • Add cross-platform device tests ensuring raw messages and JS invoke completions from a different origin are ignored.
File summaries
File Description
src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.Windows.cs Filters incoming WebView2 messages by args.Source origin before dispatch.
src/Core/src/Handlers/HybridWebView/HybridWebViewHandler.iOS.cs Filters incoming WKScriptMessage by frame request URL origin before dispatch.
src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_MessageOrigins.cs Adds shared origin-negative regression tests and shared HTML payload.
src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_MessageOrigins.Windows.cs Implements Windows-specific loading of the other-origin HTML via resource interception.
src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_MessageOrigins.iOS.cs Implements iOS/MacCatalyst loading of the other-origin HTML via LoadHtmlString.
src/Controls/tests/DeviceTests/Elements/HybridWebView/HybridWebViewTests_MessageOrigins.Android.cs Implements Android-specific loading + verifies the app-origin message endpoint was attempted.
Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 2
  • Review effort level: Lite

kubaflo
kubaflo previously approved these changes Sep 1, 2026
@kubaflo

kubaflo commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).

Copilot AI review requested due to automatic review settings September 1, 2026 22:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The implementation matches the PR description, introduces consistent cross-platform origin validation, and includes device-test coverage for the new behavior.

Review details
  • Files reviewed: 6/6 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@kubaflo
kubaflo changed the base branch from main to inflight/current September 2, 2026 14:14
@mattleibow

This comment has been minimized.

@github-actions github-actions Bot added the s/agent-review-in-progress AI review is currently running for this PR label Sep 2, 2026
@MauiBot

MauiBot commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

⚠️ Merge Conflict Detected — This PR conflicts with its target branch inflight/current. Please rebase onto the target branch and resolve the conflicts.

@MauiBot MauiBot removed the s/agent-review-in-progress AI review is currently running for this PR label Sep 2, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
@mattleibow
mattleibow force-pushed the mattleibow-hybridwebview-message-origin branch from 0cda74d to 4415a5d Compare September 2, 2026 15:55
@kubaflo
kubaflo merged commit daf8cbd into inflight/current Sep 2, 2026
7 of 38 checks passed
@kubaflo
kubaflo deleted the mattleibow-hybridwebview-message-origin branch September 2, 2026 16:33
kubaflo pushed a commit that referenced this pull request Sep 2, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

`HybridWebView` uses platform-specific mechanisms to receive messages
from its hosted content. The Windows and Apple callbacks exposed the
sender location, but that value was not used when forwarding messages to
the shared handler:

- Windows forwarded `CoreWebView2WebMessageReceivedEventArgs` payloads
without checking `Source`.
- iOS and Mac Catalyst substituted `AppOriginUri` instead of using the
URL from `WKScriptMessage.FrameInfo`.

As a result, message processing remained active when the same control
displayed content outside the app content URI.

### Description of Change

This change validates the sender before dispatching incoming messages:

- **Windows:** parses `CoreWebView2WebMessageReceivedEventArgs.Source`
and continues only when it is within `AppOriginUri`.
- **iOS and Mac Catalyst:** passes
`WKScriptMessage.FrameInfo.Request.Url` into the message path and
applies the same `AppOriginUri.IsBaseOf(...)` check.
- **Android:** keeps the existing runtime implementation. Android
already routes page-to-.NET messages through the app URI endpoint and
validates the request location before dispatching.

Messages with a missing, malformed, or different source URI are ignored.
The source URL is not included in diagnostic output.

The implementation intentionally uses the existing `Uri.TryCreate(...)`
and `AppOriginUri.IsBaseOf(...)` pattern rather than adding another URI
comparison helper. This matches the existing WebView message and
resource-routing code.

### Compatibility

- No public API changes.
- No new dependencies.
- Messages from packaged app content continue through the existing
shared parser.
- Android behavior is unchanged.
- Content outside the app URI can still be displayed; only its messages
are excluded from the app message path.

### Regression Coverage

Added Controls device tests that replace the packaged page with
deterministic HTML at a different origin in the same `HybridWebView`.
The tests verify that:

- `RawMessageReceived` is not raised for a raw message from that
document.
- A JavaScript completion message from that document does not complete a
pending invocation task.
- The replacement document finished loading before either assertion, so
a navigation failure cannot make the test pass.

The test content is provided locally:

- Windows and Android return the HTML through `WebResourceRequested`.
- iOS and Mac Catalyst load the HTML with a separate base URL.
- Android additionally verifies that the app URI endpoint was attempted
before asserting that no message was dispatched.

No external network service is required by these tests.

### Validation

- **Fail-before check:** both new tests fail without the Windows/Apple
handler changes and pass with them.
- **Mac Catalyst:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **iOS:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **Android:** 100 tests run, 95 passed, 0 failed, 5 existing skips.
- **Windows:** Windows-specific regression coverage is included; runtime
execution was not available on the current macOS host.

### Issues Fixed

N/A

---------

Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo added a commit that referenced this pull request Sep 2, 2026
…38126)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

Backports #38079 and #38078 to `inflight/candidate`.

### Changes

- Backports the Android `BlazorWebView` intent-link resolution fix from
#38079.
- Backports the cross-platform `HybridWebView` message-origin validation
fix from #38078.
- Includes the device-test coverage from both source PRs.

The landed squash commits were cherry-picked in landing order without
conflicts.

### Validation

- `dotnet build Microsoft.Maui.BuildTasks.slnf -c Debug`
- `dotnet build
src/BlazorWebView/tests/DeviceTests/MauiBlazorWebView.DeviceTests.csproj
-f net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-maccatalyst -c Debug`
- Windows cross-build reaches the Windows-only `MakePri.exe` step and
cannot complete on macOS.

---------

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c2a40510-33c4-4ff0-87f3-535f4a7e98a3
Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo added a commit that referenced this pull request Sep 3, 2026
…38126)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

Backports #38079 and #38078 to `inflight/candidate`.

### Changes

- Backports the Android `BlazorWebView` intent-link resolution fix from
#38079.
- Backports the cross-platform `HybridWebView` message-origin validation
fix from #38078.
- Includes the device-test coverage from both source PRs.

The landed squash commits were cherry-picked in landing order without
conflicts.

### Validation

- `dotnet build Microsoft.Maui.BuildTasks.slnf -c Debug`
- `dotnet build
src/BlazorWebView/tests/DeviceTests/MauiBlazorWebView.DeviceTests.csproj
-f net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-maccatalyst -c Debug`
- Windows cross-build reaches the Windows-only `MakePri.exe` step and
cannot complete on macOS.

---------

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c2a40510-33c4-4ff0-87f3-535f4a7e98a3
Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo pushed a commit that referenced this pull request Sep 3, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

`HybridWebView` uses platform-specific mechanisms to receive messages
from its hosted content. The Windows and Apple callbacks exposed the
sender location, but that value was not used when forwarding messages to
the shared handler:

- Windows forwarded `CoreWebView2WebMessageReceivedEventArgs` payloads
without checking `Source`.
- iOS and Mac Catalyst substituted `AppOriginUri` instead of using the
URL from `WKScriptMessage.FrameInfo`.

As a result, message processing remained active when the same control
displayed content outside the app content URI.

### Description of Change

This change validates the sender before dispatching incoming messages:

- **Windows:** parses `CoreWebView2WebMessageReceivedEventArgs.Source`
and continues only when it is within `AppOriginUri`.
- **iOS and Mac Catalyst:** passes
`WKScriptMessage.FrameInfo.Request.Url` into the message path and
applies the same `AppOriginUri.IsBaseOf(...)` check.
- **Android:** keeps the existing runtime implementation. Android
already routes page-to-.NET messages through the app URI endpoint and
validates the request location before dispatching.

Messages with a missing, malformed, or different source URI are ignored.
The source URL is not included in diagnostic output.

The implementation intentionally uses the existing `Uri.TryCreate(...)`
and `AppOriginUri.IsBaseOf(...)` pattern rather than adding another URI
comparison helper. This matches the existing WebView message and
resource-routing code.

### Compatibility

- No public API changes.
- No new dependencies.
- Messages from packaged app content continue through the existing
shared parser.
- Android behavior is unchanged.
- Content outside the app URI can still be displayed; only its messages
are excluded from the app message path.

### Regression Coverage

Added Controls device tests that replace the packaged page with
deterministic HTML at a different origin in the same `HybridWebView`.
The tests verify that:

- `RawMessageReceived` is not raised for a raw message from that
document.
- A JavaScript completion message from that document does not complete a
pending invocation task.
- The replacement document finished loading before either assertion, so
a navigation failure cannot make the test pass.

The test content is provided locally:

- Windows and Android return the HTML through `WebResourceRequested`.
- iOS and Mac Catalyst load the HTML with a separate base URL.
- Android additionally verifies that the app URI endpoint was attempted
before asserting that no message was dispatched.

No external network service is required by these tests.

### Validation

- **Fail-before check:** both new tests fail without the Windows/Apple
handler changes and pass with them.
- **Mac Catalyst:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **iOS:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **Android:** 100 tests run, 95 passed, 0 failed, 5 existing skips.
- **Windows:** Windows-specific regression coverage is included; runtime
execution was not available on the current macOS host.

### Issues Fixed

N/A

---------

Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo added a commit that referenced this pull request Sep 4, 2026
…38126)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

Backports #38079 and #38078 to `inflight/candidate`.

### Changes

- Backports the Android `BlazorWebView` intent-link resolution fix from
#38079.
- Backports the cross-platform `HybridWebView` message-origin validation
fix from #38078.
- Includes the device-test coverage from both source PRs.

The landed squash commits were cherry-picked in landing order without
conflicts.

### Validation

- `dotnet build Microsoft.Maui.BuildTasks.slnf -c Debug`
- `dotnet build
src/BlazorWebView/tests/DeviceTests/MauiBlazorWebView.DeviceTests.csproj
-f net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-maccatalyst -c Debug`
- Windows cross-build reaches the Windows-only `MakePri.exe` step and
cannot complete on macOS.

---------

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c2a40510-33c4-4ff0-87f3-535f4a7e98a3
Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo pushed a commit that referenced this pull request Sep 6, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

`HybridWebView` uses platform-specific mechanisms to receive messages
from its hosted content. The Windows and Apple callbacks exposed the
sender location, but that value was not used when forwarding messages to
the shared handler:

- Windows forwarded `CoreWebView2WebMessageReceivedEventArgs` payloads
without checking `Source`.
- iOS and Mac Catalyst substituted `AppOriginUri` instead of using the
URL from `WKScriptMessage.FrameInfo`.

As a result, message processing remained active when the same control
displayed content outside the app content URI.

### Description of Change

This change validates the sender before dispatching incoming messages:

- **Windows:** parses `CoreWebView2WebMessageReceivedEventArgs.Source`
and continues only when it is within `AppOriginUri`.
- **iOS and Mac Catalyst:** passes
`WKScriptMessage.FrameInfo.Request.Url` into the message path and
applies the same `AppOriginUri.IsBaseOf(...)` check.
- **Android:** keeps the existing runtime implementation. Android
already routes page-to-.NET messages through the app URI endpoint and
validates the request location before dispatching.

Messages with a missing, malformed, or different source URI are ignored.
The source URL is not included in diagnostic output.

The implementation intentionally uses the existing `Uri.TryCreate(...)`
and `AppOriginUri.IsBaseOf(...)` pattern rather than adding another URI
comparison helper. This matches the existing WebView message and
resource-routing code.

### Compatibility

- No public API changes.
- No new dependencies.
- Messages from packaged app content continue through the existing
shared parser.
- Android behavior is unchanged.
- Content outside the app URI can still be displayed; only its messages
are excluded from the app message path.

### Regression Coverage

Added Controls device tests that replace the packaged page with
deterministic HTML at a different origin in the same `HybridWebView`.
The tests verify that:

- `RawMessageReceived` is not raised for a raw message from that
document.
- A JavaScript completion message from that document does not complete a
pending invocation task.
- The replacement document finished loading before either assertion, so
a navigation failure cannot make the test pass.

The test content is provided locally:

- Windows and Android return the HTML through `WebResourceRequested`.
- iOS and Mac Catalyst load the HTML with a separate base URL.
- Android additionally verifies that the app URI endpoint was attempted
before asserting that no message was dispatched.

No external network service is required by these tests.

### Validation

- **Fail-before check:** both new tests fail without the Windows/Apple
handler changes and pass with them.
- **Mac Catalyst:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **iOS:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **Android:** 100 tests run, 95 passed, 0 failed, 5 existing skips.
- **Windows:** Windows-specific regression coverage is included; runtime
execution was not available on the current macOS host.

### Issues Fixed

N/A

---------

Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo pushed a commit that referenced this pull request Sep 7, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

`HybridWebView` uses platform-specific mechanisms to receive messages
from its hosted content. The Windows and Apple callbacks exposed the
sender location, but that value was not used when forwarding messages to
the shared handler:

- Windows forwarded `CoreWebView2WebMessageReceivedEventArgs` payloads
without checking `Source`.
- iOS and Mac Catalyst substituted `AppOriginUri` instead of using the
URL from `WKScriptMessage.FrameInfo`.

As a result, message processing remained active when the same control
displayed content outside the app content URI.

### Description of Change

This change validates the sender before dispatching incoming messages:

- **Windows:** parses `CoreWebView2WebMessageReceivedEventArgs.Source`
and continues only when it is within `AppOriginUri`.
- **iOS and Mac Catalyst:** passes
`WKScriptMessage.FrameInfo.Request.Url` into the message path and
applies the same `AppOriginUri.IsBaseOf(...)` check.
- **Android:** keeps the existing runtime implementation. Android
already routes page-to-.NET messages through the app URI endpoint and
validates the request location before dispatching.

Messages with a missing, malformed, or different source URI are ignored.
The source URL is not included in diagnostic output.

The implementation intentionally uses the existing `Uri.TryCreate(...)`
and `AppOriginUri.IsBaseOf(...)` pattern rather than adding another URI
comparison helper. This matches the existing WebView message and
resource-routing code.

### Compatibility

- No public API changes.
- No new dependencies.
- Messages from packaged app content continue through the existing
shared parser.
- Android behavior is unchanged.
- Content outside the app URI can still be displayed; only its messages
are excluded from the app message path.

### Regression Coverage

Added Controls device tests that replace the packaged page with
deterministic HTML at a different origin in the same `HybridWebView`.
The tests verify that:

- `RawMessageReceived` is not raised for a raw message from that
document.
- A JavaScript completion message from that document does not complete a
pending invocation task.
- The replacement document finished loading before either assertion, so
a navigation failure cannot make the test pass.

The test content is provided locally:

- Windows and Android return the HTML through `WebResourceRequested`.
- iOS and Mac Catalyst load the HTML with a separate base URL.
- Android additionally verifies that the app URI endpoint was attempted
before asserting that no message was dispatched.

No external network service is required by these tests.

### Validation

- **Fail-before check:** both new tests fail without the Windows/Apple
handler changes and pass with them.
- **Mac Catalyst:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **iOS:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **Android:** 100 tests run, 95 passed, 0 failed, 5 existing skips.
- **Windows:** Windows-specific regression coverage is included; runtime
execution was not available on the current macOS host.

### Issues Fixed

N/A

---------

Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo added a commit that referenced this pull request Sep 7, 2026
…38126)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

Backports #38079 and #38078 to `inflight/candidate`.

### Changes

- Backports the Android `BlazorWebView` intent-link resolution fix from
#38079.
- Backports the cross-platform `HybridWebView` message-origin validation
fix from #38078.
- Includes the device-test coverage from both source PRs.

The landed squash commits were cherry-picked in landing order without
conflicts.

### Validation

- `dotnet build Microsoft.Maui.BuildTasks.slnf -c Debug`
- `dotnet build
src/BlazorWebView/tests/DeviceTests/MauiBlazorWebView.DeviceTests.csproj
-f net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-maccatalyst -c Debug`
- Windows cross-build reaches the Windows-only `MakePri.exe` step and
cannot complete on macOS.

---------

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c2a40510-33c4-4ff0-87f3-535f4a7e98a3
Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo pushed a commit that referenced this pull request Sep 8, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

`HybridWebView` uses platform-specific mechanisms to receive messages
from its hosted content. The Windows and Apple callbacks exposed the
sender location, but that value was not used when forwarding messages to
the shared handler:

- Windows forwarded `CoreWebView2WebMessageReceivedEventArgs` payloads
without checking `Source`.
- iOS and Mac Catalyst substituted `AppOriginUri` instead of using the
URL from `WKScriptMessage.FrameInfo`.

As a result, message processing remained active when the same control
displayed content outside the app content URI.

### Description of Change

This change validates the sender before dispatching incoming messages:

- **Windows:** parses `CoreWebView2WebMessageReceivedEventArgs.Source`
and continues only when it is within `AppOriginUri`.
- **iOS and Mac Catalyst:** passes
`WKScriptMessage.FrameInfo.Request.Url` into the message path and
applies the same `AppOriginUri.IsBaseOf(...)` check.
- **Android:** keeps the existing runtime implementation. Android
already routes page-to-.NET messages through the app URI endpoint and
validates the request location before dispatching.

Messages with a missing, malformed, or different source URI are ignored.
The source URL is not included in diagnostic output.

The implementation intentionally uses the existing `Uri.TryCreate(...)`
and `AppOriginUri.IsBaseOf(...)` pattern rather than adding another URI
comparison helper. This matches the existing WebView message and
resource-routing code.

### Compatibility

- No public API changes.
- No new dependencies.
- Messages from packaged app content continue through the existing
shared parser.
- Android behavior is unchanged.
- Content outside the app URI can still be displayed; only its messages
are excluded from the app message path.

### Regression Coverage

Added Controls device tests that replace the packaged page with
deterministic HTML at a different origin in the same `HybridWebView`.
The tests verify that:

- `RawMessageReceived` is not raised for a raw message from that
document.
- A JavaScript completion message from that document does not complete a
pending invocation task.
- The replacement document finished loading before either assertion, so
a navigation failure cannot make the test pass.

The test content is provided locally:

- Windows and Android return the HTML through `WebResourceRequested`.
- iOS and Mac Catalyst load the HTML with a separate base URL.
- Android additionally verifies that the app URI endpoint was attempted
before asserting that no message was dispatched.

No external network service is required by these tests.

### Validation

- **Fail-before check:** both new tests fail without the Windows/Apple
handler changes and pass with them.
- **Mac Catalyst:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **iOS:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **Android:** 100 tests run, 95 passed, 0 failed, 5 existing skips.
- **Windows:** Windows-specific regression coverage is included; runtime
execution was not available on the current macOS host.

### Issues Fixed

N/A

---------

Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo added a commit that referenced this pull request Sep 8, 2026
…38126)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

Backports #38079 and #38078 to `inflight/candidate`.

### Changes

- Backports the Android `BlazorWebView` intent-link resolution fix from
#38079.
- Backports the cross-platform `HybridWebView` message-origin validation
fix from #38078.
- Includes the device-test coverage from both source PRs.

The landed squash commits were cherry-picked in landing order without
conflicts.

### Validation

- `dotnet build Microsoft.Maui.BuildTasks.slnf -c Debug`
- `dotnet build
src/BlazorWebView/tests/DeviceTests/MauiBlazorWebView.DeviceTests.csproj
-f net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-maccatalyst -c Debug`
- Windows cross-build reaches the Windows-only `MakePri.exe` step and
cannot complete on macOS.

---------

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c2a40510-33c4-4ff0-87f3-535f4a7e98a3
Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo pushed a commit that referenced this pull request Sep 9, 2026
<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

### Root Cause

`HybridWebView` uses platform-specific mechanisms to receive messages
from its hosted content. The Windows and Apple callbacks exposed the
sender location, but that value was not used when forwarding messages to
the shared handler:

- Windows forwarded `CoreWebView2WebMessageReceivedEventArgs` payloads
without checking `Source`.
- iOS and Mac Catalyst substituted `AppOriginUri` instead of using the
URL from `WKScriptMessage.FrameInfo`.

As a result, message processing remained active when the same control
displayed content outside the app content URI.

### Description of Change

This change validates the sender before dispatching incoming messages:

- **Windows:** parses `CoreWebView2WebMessageReceivedEventArgs.Source`
and continues only when it is within `AppOriginUri`.
- **iOS and Mac Catalyst:** passes
`WKScriptMessage.FrameInfo.Request.Url` into the message path and
applies the same `AppOriginUri.IsBaseOf(...)` check.
- **Android:** keeps the existing runtime implementation. Android
already routes page-to-.NET messages through the app URI endpoint and
validates the request location before dispatching.

Messages with a missing, malformed, or different source URI are ignored.
The source URL is not included in diagnostic output.

The implementation intentionally uses the existing `Uri.TryCreate(...)`
and `AppOriginUri.IsBaseOf(...)` pattern rather than adding another URI
comparison helper. This matches the existing WebView message and
resource-routing code.

### Compatibility

- No public API changes.
- No new dependencies.
- Messages from packaged app content continue through the existing
shared parser.
- Android behavior is unchanged.
- Content outside the app URI can still be displayed; only its messages
are excluded from the app message path.

### Regression Coverage

Added Controls device tests that replace the packaged page with
deterministic HTML at a different origin in the same `HybridWebView`.
The tests verify that:

- `RawMessageReceived` is not raised for a raw message from that
document.
- A JavaScript completion message from that document does not complete a
pending invocation task.
- The replacement document finished loading before either assertion, so
a navigation failure cannot make the test pass.

The test content is provided locally:

- Windows and Android return the HTML through `WebResourceRequested`.
- iOS and Mac Catalyst load the HTML with a separate base URL.
- Android additionally verifies that the app URI endpoint was attempted
before asserting that no message was dispatched.

No external network service is required by these tests.

### Validation

- **Fail-before check:** both new tests fail without the Windows/Apple
handler changes and pass with them.
- **Mac Catalyst:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **iOS:** 97 tests run, 96 passed, 0 failed, 1 existing skip.
- **Android:** 100 tests run, 95 passed, 0 failed, 5 existing skips.
- **Windows:** Windows-specific regression coverage is included; runtime
execution was not available on the current macOS host.

### Issues Fixed

N/A

---------

Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
kubaflo added a commit that referenced this pull request Sep 9, 2026
…38126)

<!-- Please let the below note in for people that find this PR -->
> [!NOTE]
> Are you waiting for the changes in this PR to be merged?
> It would be very helpful if you could [test the resulting
artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from
this PR and let us know in a comment if this change resolves your issue.
Thank you!

Backports #38079 and #38078 to `inflight/candidate`.

### Changes

- Backports the Android `BlazorWebView` intent-link resolution fix from
#38079.
- Backports the cross-platform `HybridWebView` message-origin validation
fix from #38078.
- Includes the device-test coverage from both source PRs.

The landed squash commits were cherry-picked in landing order without
conflicts.

### Validation

- `dotnet build Microsoft.Maui.BuildTasks.slnf -c Debug`
- `dotnet build
src/BlazorWebView/tests/DeviceTests/MauiBlazorWebView.DeviceTests.csproj
-f net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-android -c Debug`
- `dotnet build
src/Controls/tests/DeviceTests/Controls.DeviceTests.csproj -f
net10.0-maccatalyst -c Debug`
- Windows cross-build reaches the Windows-only `MakePri.exe` step and
cannot complete on macOS.

---------

Co-authored-by: Matthew Leibowitz <mattleibow@live.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c2a40510-33c4-4ff0-87f3-535f4a7e98a3
Copilot-Session: a5d3b169-5cb5-440d-a4ba-22e39d132876
@github-actions github-actions Bot locked and limited conversation to collaborators Oct 3, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-controls-hybridwebview HybridWebView control platform/android platform/ios platform/macos macOS / Mac Catalyst platform/windows s/agent-approved AI agent recommends approval - PR fix is correct and optimal s/agent-fix-pr-picked AI could not beat the PR fix - PR is the best among all candidates s/agent-reviewed PR was reviewed by AI agent workflow (full 4-phase review)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants