CVE-2026-113320
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifios/web/web_state/ui/crw_web_controller.mm |
modified |
Files Changed
ios/testing/http_server_bundle_data.filelistios/chrome/browser/web/model/BUILD.gnios/chrome/browser/web/model/web_drag_drop_egtest.mmios/testing/data/http_server_files/javascript_link.htmlios/web/web_state/ui/crw_web_controller.mmios/testing/data/http_server_files/iframe_drag_link.htmlios/testing/data/http_server_files/link.html
Patch
From 1efe836112ba7e7018f0b5a83eac05883f4d494c Mon Sep 17 00:00:00 2001 From: Mike Dougherty <[email protected]> Date: Fri, 18 Sep 2026 14:09:26 -0700 Subject: [PATCH] [iOS] Update logic to open drag and dropped URLs in a new tab Previously, URLs dropped onto a tab would open within that tab. This CL updates the logic to match Chrome on other platforms where dropped URLs now open a new tab. Additionally, add `aria-label` to link in link.html in order to support the existing `LongPressLinkAndDragToView` helper and add a new `javascript_link.html` file to support testing of a javascript link. Fixed: 429432679 Change-Id: I14fc46dea73859dbfe733b275ceceb2e11c711bc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8425547 Reviewed-by: Gauthier Ambard <[email protected]> Commit-Queue: Mike Dougherty <[email protected]> Cr-Commit-Position: refs/heads/main@{#1701076} --- diff --git a/ios/chrome/browser/web/model/web_drag_drop_egtest.mm b/ios/chrome/browser/web/model/web_drag_drop_egtest.mm new file mode 100644 index 0000000..0e93ab97 --- /dev/null +++ b/ios/chrome/browser/web/model/web_drag_drop_egtest.mm @@ -0,0 +1,106 @@ +// Copyright 2026 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "ios/chrome/test/earl_grey/chrome_earl_grey.h" +#import "ios/chrome/test/earl_grey/chrome_test_case.h" +#import "ios/chrome/test/earl_grey/chrome_xcui_actions.h" +#import "ios/testing/earl_grey/earl_grey_test.h" +#import "net/test/embedded_test_server/embedded_test_server.h" +#import "url/gurl.h" + +namespace { + +// Initiates a drag on the `link` element and drops it to the lower right of the +// web view. +bool LongPressLinkAndDragDropToWebView() { + // Offset for dropping items onto the web view to avoid ending the drag within + // the context menu bounds. + CGVector kLowerRightWindowOffset = {0.85, 0.85}; + return chrome_test_util::LongPressLinkAndDragToView( + @"link", /*src_window_number=*/0, /*dst_accessibility_identifier=*/nil, + /*dst_window_number=*/0, kLowerRightWindowOffset); +} + +} // namespace + +// Test case for drag and drop interactions in web content. +@interface WebDragDropTestCase : ChromeTestCase +@end + +@implementation WebDragDropTestCase + +- (void)setUp { + [super setUp]; + GREYAssertTrue(self.testServer->Start(), @"Server did not start."); +} + +// Tests that dragging and dropping a web link opens the URL in a new tab. +- (void)testDragAndDropLink { + [ChromeEarlGrey loadURL:self.testServer->GetURL("/link.html")]; + [ChromeEarlGrey waitForWebStateContainingText:"Link"]; + + GREYAssert(LongPressLinkAndDragDropToWebView(), + @"Failed to drag link to view"); + + [ChromeEarlGrey waitForMainTabCount:2]; + const GURL expectedURL = self.testServer->GetURL("/pony.html"); + [ChromeEarlGrey waitForWebStateVisibleURL:expectedURL]; + [ChromeEarlGrey + waitForWebStateContainingText:"Anyone know any good pony jokes?"]; +} + +// Tests that dragging and dropping a web link in an incognito tab opens the URL +// in a new incognito tab. +- (void)testDragAndDropLinkInIncognito { + [ChromeEarlGrey openNewIncognitoTab]; + [ChromeEarlGrey closeAllNormalTabs]; + + [ChromeEarlGrey waitForIncognitoTabCount:1]; + [ChromeEarlGrey waitForMainTabCount:0]; + + [ChromeEarlGrey loadURL:self.testServer->GetURL("/link.html")]; + [ChromeEarlGrey waitForWebStateContainingText:"Link"]; + + GREYAssert(LongPressLinkAndDragDropToWebView(), + @"Failed to drag link to view"); + + [ChromeEarlGrey waitForIncognitoTabCount:2]; + [ChromeEarlGrey waitForMainTabCount:0]; + const GURL expectedURL = self.testServer->GetURL("/pony.html"); + [ChromeEarlGrey waitForWebStateVisibleURL:expectedURL]; + [ChromeEarlGrey + waitForWebStateContainingText:"Anyone know any good pony jokes?"]; +} + +// Tests that dragging and dropping a link with a disallowed scheme (e.g. +// javascript:) does not open a new tab or navigate. +- (void)testDragAndDropDisallowedSchemeDoesNotNavigate { + const GURL initialURL = self.testServer->GetURL("/javascript_link.html"); + [ChromeEarlGrey loadURL:initialURL]; + [ChromeEarlGrey waitForWebStateContainingText:"Link"]; + + GREYAssert(LongPressLinkAndDragDropToWebView(), + @"Failed to drag link to view"); + + [ChromeEarlGrey waitForMainTabCount:1]; + [ChromeEarlGrey waitForWebStateVisibleURL:initialURL]; +} + +// Tests that dragging and dropping a link embedded in an iframe opens the URL +// in a new tab. +- (void)testDragAndDropLinkFromIframe { + [ChromeEarlGrey loadURL:self.testServer->GetURL("/iframe_drag_link.html")]; + [ChromeEarlGrey waitForWebStateContainingText:"Iframe Loaded"]; + + GREYAssert(LongPressLinkAndDragDropToWebView(), + @"Failed to drag link to view"); + + [ChromeEarlGrey waitForMainTabCount:2]; + const GURL expectedURL = self.testServer->GetURL("/pony.html"); + [ChromeEarlGrey waitForWebStateVisibleURL:expectedURL]; + [ChromeEarlGrey + waitForWebStateContainingText:"Anyone know any good pony jokes?"]; +} + +@end diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 9505481..7e0009d 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm @@ -52,9 +52,11 @@ #import "ios/web/public/content_type_util.h" #import "ios/web/public/find_in_page/crw_find_interaction.h" #import "ios/web/public/js_messaging/web_frames_manager.h" +#import "ios/web/public/navigation/referrer.h" #import "ios/web/public/permissions/permissions.h" #import "ios/web/public/ui/crw_web_view_scroll_view_proxy.h" #import "ios/web/public/web_client.h" +#import "ios/web/public/web_state.h" #import "ios/web/security/crw_cert_verification_controller.h" #import "ios/web/security/crw_ssl_status_updater.h" #import "ios/web/util/wk_web_view_util.h" @@ -74,6 +76,7 @@ #import "ios/web/web_state/web_view_pass_key.h" #import "net/base/apple/url_conversions.h" #import "services/metrics/public/cpp/ukm_builders.h" +#import "ui/base/window_open_disposition.h" #import "url/gurl.h" #import "url/origin.h" @@ -2028,12 +2031,18 @@ } - (void)loadUrlObjectsCompletion:(NSArray<NSURL*>*)objects { - GURL URL = net::GURLWithNSURL([objects firstObject]); - if (!_isBeingDestroyed && URL.is_valid() && URL.SchemeIsHTTPOrHTTPS()) { - web::NavigationManager::WebLoadParams params(URL); - params.transition_type = ui::PAGE_TRANSITION_TYPED; - self.webStateImpl->GetNavigationManager()->LoadURLWithParams(params); + if (_isBeingDestroyed || !self.webStateImpl) { + return; } + GURL URL = net::GURLWithNSURL([objects firstObject]); + if (!URL.is_valid() || !URL.SchemeIsHTTPOrHTTPS()) { + return; + } + web::WebState::OpenURLParams params(URL, web::Referrer(), + WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui::PAGE_TRANSITION_LINK, + /*is_renderer_initiated=*/false); + self.webStateImpl->OpenURL(params); } #pragma mark - Testing-Only Methods diff --git a/ios/testing/data/http_server_files/iframe_drag_link.html b/ios/testing/data/http_server_files/iframe_drag_link.html new file mode 100644 index 0000000..75eb748 --- /dev/null +++ b/ios/testing/data/http_server_files/iframe_drag_link.html @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<!-- +Copyright 2026 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> +<html> + <head> + <title>Iframe Drag Link</title> + </head> + <body> + <iframe src="link.html" style="width:200px;height:200px;border:none;" onload="document.body.appendChild(document.createTextNode('Iframe Loaded'));"></iframe> + </body> +</html> diff --git a/ios/testing/data/http_server_files/javascript_link.html b/ios/testing/data/http_server_files/javascript_link.html new file mode 100644 index 0000000..bdbb83a --- /dev/null +++ b/ios/testing/data/http_server_files/javascript_link.html @@ -0,0 +1,18 @@ +<!DOCTYPE html> + +<!-- +Copyright 2026 The Chromium Authors +Use of this source code is governed by a BSD-style license that can be +found in the LICENSE file. +--> + +<!-- +This file contains a link with a javascript: URL scheme. The link is at a +precise position to be able to tap it. +--> + +<html> + <body> + <a href="javascript:void(0);" id="link" aria-label="link" style="display:inline-block;position:absolute;left:40px;top:40px;width:10px;height:10px;">Link</a> + </body> +</html> diff --git a/ios/testing/data/http_server_files/link.html b/ios/testing/data/http_server_files/link.html index 6c5b0f7..8bfbbee 100644 --- a/ios/testing/data/http_server_files/link.html +++ b/ios/testing/data/http_server_files/link.html @@ -13,6 +13,6 @@ <html> <body> - <a href="pony.html" id="link" style="display:inline-block;position:absolute;left:40px;top:40px;width:10px;height:10px;">Link</a> + <a href="pony.html" id="link" aria-label="link" style="display:inline-block;position:absolute;left:40px;top:40px;width:10px;height:10px;">Link</a> </body> </html> diff --git a/ios/testing/http_server_bundle_data.filelist b/ios/testing/http_server_bundle_data.filelist index 3f6c0aa..85ece72 100644 --- a/ios/testing/http_server_bundle_data.filelist +++ b/ios/testing/http_server_bundle_data.filelist @@ -37,9 +37,11 @@ data/http_server_files/history.js data/http_server_files/history_go.html data/http_server_files/history_go.js +data/http_server_files/iframe_drag_link.html data/http_server_files/iframe_form.html data/http_server_files/iframe_host.html data/http_server_files/insecure_form.html +data/http_server_files/javascript_link.html data/http_server_files/link.html data/http_server_files/links.html data/http_server_files/memory_usage.html diff --git a/ios/chrome/browser/web/model/BUILD.gn b/ios/chrome/browser/web/model/BUILD.gn index e5ad106..9b5ee2f 100644 --- a/ios/chrome/browser/web/model/BUILD.gn +++ b/ios/chrome/browser/web/model/BUILD.gn @@ -519,6 +519,7 @@ "stop_loading_egtest.mm", "tab_order_egtest.mm", "visible_url_egtest.mm", + "web_drag_drop_egtest.mm", "web_share_egtest.mm", "window_open_by_dom_egtest.mm", ]
Regression Test / PoC
diff --git a/ios/testing/data/http_server_files/iframe_drag_link.html b/ios/testing/data/http_server_files/iframe_drag_link.html
new file mode 100644
index 0000000..75eb748
--- /dev/null
+++ b/ios/testing/data/http_server_files/iframe_drag_link.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<!--
+Copyright 2026 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+<html>
+ <head>
+ <title>Iframe Drag Link</title>
+ </head>
+ <body>
+ <iframe src="link.html" style="width:200px;height:200px;border:none;" onload="document.body.appendChild(document.createTextNode('Iframe Loaded'));"></iframe>
+ </body>
+</html>
diff --git a/ios/testing/data/http_server_files/javascript_link.html b/ios/testing/data/http_server_files/javascript_link.html
new file mode 100644
index 0000000..bdbb83a
--- /dev/null
+++ b/ios/testing/data/http_server_files/javascript_link.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+
+<!--
+Copyright 2026 The Chromium Authors
+Use of this source code is governed by a BSD-style license that can be
+found in the LICENSE file.
+-->
+
+<!--
+This file contains a link with a javascript: URL scheme. The link is at a
+precise position to be able to tap it.
+-->
+
+<html>
+ <body>
+ <a href="javascript:void(0);" id="link" aria-label="link" style="display:inline-block;position:absolute;left:40px;top:40px;width:10px;height:10px;">Link</a>
+ </body>
+</html>
diff --git a/ios/testing/data/http_server_files/link.html b/ios/testing/data/http_server_files/link.html
index 6c5b0f7..8bfbbee 100644
--- a/ios/testing/data/http_server_files/link.html
+++ b/ios/testing/data/http_server_files/link.html
@@ -13,6 +13,6 @@
<html>
<body>
- <a href="pony.html" id="link" style="display:inline-block;position:absolute;left:40px;top:40px;width:10px;height:10px;">Link</a>
+ <a href="pony.html" id="link" aria-label="link" style="display:inline-block;position:absolute;left:40px;top:40px;width:10px;height:10px;">Link</a>
</body>
</html>
diff --git a/ios/testing/http_server_bundle_data.filelist b/ios/testing/http_server_bundle_data.filelist
index 3f6c0aa..85ece72 100644
--- a/ios/testing/http_server_bundle_data.filelist
+++ b/ios/testing/http_server_bundle_data.filelist
@@ -37,9 +37,11 @@
data/http_server_files/history.js
data/http_server_files/history_go.html
data/http_server_files/history_go.js
+data/http_server_files/iframe_drag_link.html
data/http_server_files/iframe_form.html
data/http_server_files/iframe_host.html
data/http_server_files/insecure_form.html
+data/http_server_files/javascript_link.html
data/http_server_files/link.html
data/http_server_files/links.html
data/http_server_files/memory_usage.html
Original Bug Report
Chrome iOS Address Bar Spoof Using Cross-Origin <iframe> and Drag-Drop to a Never Loading Destination
Report description
Chrome iOS Address Bar Spoof Using Cross-Origin <iframe> and Drag-Drop to a Never Loading Destination
Bug location
Where do you want to report your vulnerability?
Chrome VRP – Report security issues affecting the Chrome browser. See program rules
The problem
Please describe the technical details of the vulnerability
If we have a location that will never load like (https://google.com:81) the browser will try to request to the site and won’t change the address bar unless we receive a response, but Chrome has a feature that allows us to redirect to location when tap and holding a link and dropping it inside the current tab. This feature when abused we can change the address bar value to the invalid address ((https://google.com:81) and with our controlled content still on the current origin. There is also another problem which is when we tap and hold a link it will display the context menu to preview the link or options to open in a new tab, but if we embed the link inside a cross-origin iframe the context menu won’t be shown and we can easily drag and drop a link into anywhere.
- POC:
https://rx23.io/poc/chrome/1.html - Tap and hold the link and drop it anywhere inside the page
- Address bar changed to
https://accounts.google.com:81/with our controlled content
My POC code explanation:
- Cross origin iframe (I’m using data: URI) with a link pointing to (https://google.com:81)
- If touchstart on the link we send a postMessage to parent domain
- Inside parent domain we have a location for dropping which it’s not necessary but just for UI
- We have a message event listener when we receive the message after couple seconds we change page contents to a fake login
POC Video also attached
Instead of an invalid port a very slow page also can be used, the link also can be customized with displaying an image or any other tricks to spoof the user.
Impact analysis – Please briefly explain who can exploit the vulnerability, and what they gain when doing so
Address bar spoof to trick users into stealing credentials and other data
The cause
What version of Chrome have you found the security issue in?
138.0.7204.119 Stable iOS
Is the security issue related to a crash?
No, it is not related to a crash.
Choose the type of vulnerability
Security UI Spoofing
How would you like to be publicly acknowledged for your report?
@RenwaX23