diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index c4c2b8d924273..8fa71ad822c85 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm @@ -378,7 +378,7 @@ void SetWebViewURL(NSString* url_string) { } // Test fixture to test JavaScriptDialogPresenter. -class JavaScriptDialogPresenterTest : public WebTestWithWebState { +class JavaScriptDialogPresenterTest : public WebTestWithWebController { protected: JavaScriptDialogPresenterTest() : page_url_("https://chromium.test/") {} void SetUp() override { @@ -468,6 +468,26 @@ void TearDown() override { EXPECT_NSEQ(@"No", dialog->default_prompt_text); } +// Tests that window.alert, window.confirm and window.prompt dialogs are not +// shown if URL of presenting main frame is different from visible URL. +TEST_F(JavaScriptDialogPresenterTest, DifferentVisibleUrl) { + ASSERT_TRUE(requested_dialogs().empty()); + + // Change visible URL. + AddPendingItem(GURL("https://pending.test/"), ui::PAGE_TRANSITION_TYPED); + web_controller().webStateImpl->SetIsLoading(true); + ASSERT_NE(page_url().GetOrigin(), web_state()->GetVisibleURL().GetOrigin()); + + ExecuteJavaScript(@"alert('test')"); + ASSERT_TRUE(requested_dialogs().empty()); + + EXPECT_NSEQ(@NO, ExecuteJavaScript(@"confirm('test')")); + ASSERT_TRUE(requested_dialogs().empty()); + + EXPECT_NSEQ([NSNull null], ExecuteJavaScript(@"prompt('Yes?', 'No')")); + ASSERT_TRUE(requested_dialogs().empty()); +} + // Test fixture for testing visible security state. typedef WebTestWithWebState CRWWebStateSecurityStateTest; diff --git a/ios/web/web_state/ui/crw_wk_ui_handler.mm b/ios/web/web_state/ui/crw_wk_ui_handler.mm index 3addb4ff3b6e7..2844baee0053e 100644 --- a/ios/web/web_state/ui/crw_wk_ui_handler.mm +++ b/ios/web/web_state/ui/crw_wk_ui_handler.mm @@ -264,6 +264,18 @@ - (void)runJavaScriptDialogOfType:(web::JavaScriptDialogType)type return; } + if (self.webStateImpl->GetVisibleURL().GetOrigin() != + requestURL.GetOrigin() && + frame.mainFrame) { + // Dialog was requested by web page's main frame, but visible URL has + // different origin. This could happen if the user has started a new + // browser initiated navigation. There is no value in showing dialogs + // requested by page, which this WebState is about to leave. But presenting + // the dialog can lead to phishing and other abusive behaviors. + completionHandler(NO, nil); + return; + } + self.webStateImpl->RunJavaScriptDialog( requestURL, type, message, defaultText, base::BindOnce(^(bool success, NSString* input) {