CVE-2026-13843
Overview
Files Changed
ios/web/webui/web_ui_messaging_java_script_feature.mm
Patch
From 3c83a4e5c8edb7b1f2ac8f230b3ad616174fcddd Mon Sep 17 00:00:00 2001
From: Mike Dougherty <michaeldo@chromium.org>
Date: Mon, 15 Jun 2026 10:38:38 -0700
Subject: [PATCH] Discard WebUI messages if the security_origin does not match the commited url.
Fixed: 516869032
Change-Id: I3b7e1493b1780b289b254acc6b7d53be7b8e54b6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7934275
Commit-Queue: Mike Dougherty <michaeldo@chromium.org>
Reviewed-by: Gauthier Ambard <gambard@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1646921}
---
diff --git a/ios/web/webui/web_ui_messaging_java_script_feature.mm b/ios/web/webui/web_ui_messaging_java_script_feature.mm
index 778f20dc..68a65ac 100644
--- a/ios/web/webui/web_ui_messaging_java_script_feature.mm
+++ b/ios/web/webui/web_ui_messaging_java_script_feature.mm
@@ -49,6 +49,13 @@
return;
}
+ if (!script_message.security_origin().IsSameOriginWith(
+ url::Origin::Create(url.value()))) {
+ // Discard the message as the committed origin does not match the request
+ // URL
+ return;
+ }
+
if (!script_message.body() || !script_message.body()->is_dict()) {
return;
}
Original Bug Report
Potential WebUI message bypass on iOS via provisional navigation request URL check
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: The WebUI message dispatcher on iOS relies on the provisional request URL rather than the committed security origin when validating incoming messages. During a provisional WebUI navigation, a compromised WebContent process can exploit this mismatch to invoke privileged WebUI message handlers before navigation commits. This creates a potential sandbox escape path from the WebContent process to the browser process.
Affected files:
ios/web/webui/web_ui_messaging_java_script_feature.mmios/web/navigation/crw_wk_navigation_handler.mmios/web/web_state/web_state_impl_realized_web_state.mm
Estimated timestamp from git blame: 2023-01-17
Root Cause Analysis
In Chrome for iOS, WebUIMessagingJavaScriptFeature::ScriptMessageReceived acts as the browser-process handler for chrome.send() WebUI messages. This function authorizes dispatch by checking that the message is from the main frame and that its URL is an app-specific URL:
// ios/web/webui/web_ui_messaging_java_script_feature.mm
void WebUIMessagingJavaScriptFeature::ScriptMessageReceived(
WebState* web_state, const ScriptMessage& script_message) {
if (!script_message.is_main_frame()) return;
std::optional<GURL> url = script_message.request_url();
if (!url || !web::GetWebClient()->IsAppSpecificURL(url.value())) return;
...
web_state_impl->HandleWebUIMessage(url.value(), *message_content, *arguments);
}
The field request_url() is populated in ios/web/js_messaging/java_script_content_world.mm from script_message.frameInfo.request.URL. This represents the provisional request URL of the frame during a navigation, which updates before the navigation actually commits.
However, the browser-side gate check in WebStateImpl::RealizedWebState::HandleWebUIMessage relies on HasWebUI():
void WebStateImpl::RealizedWebState::HandleWebUIMessage(...) {
if (!HasWebUI()) return;
web_ui_->ProcessWebUIIOSMessage(source_url, message, args);
}
Because the WebUIIOS controller is instantiated pre-commit during decidePolicyForNavigationAction in ios/web/navigation/crw_wk_navigation_handler.mm, HasWebUI() returns true before the navigation commits and while the previous document (e.g., https://evil.example) is still executing.
Since the validation checks request_url() (provisional) instead of the committed security origin of the frame (security_origin()), a compromised WebContent process can initiate a WebUI navigation and immediately post a forged message to invoke privileged WebUI handlers.
Potential Attack Scenario
Note: These are suggested/potential steps. Our tooling does not currently have the capability to execute code or run a live proof of concept to verify this behavior.
- A compromised WebContent process is active on a standard web page (e.g.,
https://evil.example). - The compromised process triggers a back-forward navigation to an app-specific WebUI URL (e.g.,
chrome://flags). - The browser process receives the provisional navigation request and instantiates the
FlagsUIcontroller pre-commit, settingHasWebUI()totrue. - Before the navigation commits, the compromised document on
https://evil.exampleposts a script message viaDidPostMessageunder the"WebUIMessage"handler. - The browser process maps the message’s
request_urlto the provisionalchrome://flagsURL and validates it as app-specific. - The browser process verifies
HasWebUI()istrueand dispatches the message toFlagsUIhandlers in the unsandboxed browser process.
Suggested Fix
Modify the message validation path in WebUIMessagingJavaScriptFeature::ScriptMessageReceived to verify the sender’s origin against the web view’s committed URL, or use the verified security_origin() of the frame to make the security decision:
if (!script_message.security_origin().IsSameOriginWith(url::Origin::Create(url.value()))) {
// Discard the message as the committed origin does not match the request URL
return;
}
Evaluated with Chrome root at commit: b1520ef4a76878853a31f0943b565e42060edec8
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
Data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.