Low watch CVSS 6.5 chrome Input Validation 🔧 Commit mapped

Overview

Low
Severity
6.5
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactImproper input validation in NTP Footer
DescriptionImproper input validation in NTP Footer
ComponentNTP Footer
Sub-componentNtp footer
Bug ClassInput Validation
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker517395590
Fix commit3bad81ace4d4 (chromium/src) +109/-4
CWECWE-20 (Improper input validation)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N
CISA KEVNot listed
CreditedOrange Tsai (@orange_8361) of DEVCORE Research Team
Reported2026-05-28 (per vendor advisory)
Fix landed2026-07-07 (public git)
Disclosed2026-08-25
Patch gap49 days — fix public in source before the advisory

Background

NTP Footer
a Top-Chrome WebUI strip rendered at the bottom of a New Tab Page tab, used to display management/extension notices and to host links the user can click.
`OpenURLFromTab`
the content::WebContentsDelegate entry point Chrome uses to service a navigation request originating from a given source WebContents, deciding which WebContents actually navigates.
Split view
a browser mode that shows two tabs side by side, so the “active” tab is not necessarily the tab a given footer is attached to.
`base::WeakPtr<content::WebContents>`
a non-owning, auto-nulling handle used here to reference the footer’s attached tab without extending its lifetime.

Root Cause Analysis

The footer WebUI’s link handler NewTabFooterHandler::OpenUrlInCurrentTab performed navigation by calling browser_window->OpenURL(params, ...), which targets the browser window’s currently active tab rather than the specific tab the footer belongs to. In a split view, the footer attached to one tab could therefore drive a navigation in a different (active) tab, violating the invariant that a footer only navigates its own attached tab context.

The fix re-plumbs navigation so the handler calls web_contents_->OpenURL(...) on the footer’s own WebUI WebContents, whose delegate (NewTabFooterWebView) now implements OpenURLFromTab to forward the request to the stored attached_tab_contents_. NewTabFooterWebView::ShowUI was extended to capture a base::WeakPtr to the attached tab’s WebContents at show time, and OpenURLFromTab returns nullptr (dropping the navigation) if that weak pointer has been invalidated. The regression test OpenUrlFromTabInSplit confirms the target URL now commits in the NTP tab and leaves the active split-view tab untouched, and OpenUrlInCurrentTab_InvalidUrl confirms an invalid URL such as https:// is not forwarded.

Key insight
The single mistake was attributing the footer’s navigation to the browser’s active tab (browser_window->OpenURL) instead of the footer’s attached tab; the fix routes the navigation through the footer WebUI’s own WebContents and a new OpenURLFromTab override bound to a weak pointer of the correct attached tab.

Attack Path

  1. Open a managed/extension NTP in split view The user has two tabs side by side, one showing an NTP whose footer is shown because a management or extension notice applies (ShouldShowExtensionFooter/managed check in footer_controller.cc).
  2. Footer is attached to the non-active tab The footer belongs to the NTP tab, but a different tab is the active WebContents of the browser window.
  3. Trigger a footer navigation Activating a footer link invokes NewTabFooterHandler::OpenUrlInCurrentTab, which pre-patch called browser_window->OpenURL, resolving to the browser’s active tab rather than the NTP tab.
  4. Navigation lands in the wrong tab The active (unrelated) tab is navigated to the footer-supplied URL, so a navigation is committed in a tab context that did not originate or expect it (cross-tab navigation context confusion).

Impact Assessment

An attacker able to influence the footer’s navigation target could cause a navigation to commit in the wrong tab (the active split-view tab rather than the footer’s own NTP tab), producing improper navigation-context attribution / a redirect of an unrelated tab. This occurs in the browser UI within the browser process, and requires the footer to be shown (managed or extension-provided NTP) and, for the cross-tab effect, a split-view arrangement where the footer’s tab is not the active tab. The vendor advisory rates this low severity and does not report in-the-wild exploitation; NVD scores it CVSS 6.5. Any further escalation is not demonstrated by the patch.

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/views/new_tab_footer/footer_controller.cc
modified
if
chrome/browser/ui/views/new_tab_footer/footer_web_view.cc
modified
IN_PROC_BROWSER_TEST_F
chrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc
modified
MockWebContentsDelegate
chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
modified
NewTabFooterHandlerExtensionTest
chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
modified
TEST_F
chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
modified
NewTabFooterHandlerEnterpriseTest
chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
modified

Files Changed

  • chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
  • chrome/browser/ui/views/new_tab_footer/footer_web_view.h
  • chrome/browser/ui/webui/new_tab_footer/BUILD.gn
  • chrome/browser/ui/views/new_tab_footer/footer_controller.cc
  • chrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc
  • chrome/browser/ui/views/new_tab_footer/footer_web_view.cc
  • chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc

Audit Directions

  • Active-tab vs. source-tab navigation
    Audit other WebUI/embedded UI handlers that call browser_window->OpenURL, Navigate, or resolve “current tab” from a Browser/window rather than from their own source WebContents, especially any surface that can exist in split view or be attached to a non-active tab.
  • Delegate routing for embedded WebContents
    Review WebContentsDelegate::OpenURLFromTab implementations (and their absence) on embedded WebUI views to ensure navigations are routed to the intended target and safely no-op when the target WebContents has been destroyed.
  • Lifetime of cached tab references
    Look for cached raw pointers to attached tabs in UI controllers that should be WeakPtrs, where a stale reference could redirect or crash on navigation after tab close.
From 3bad81ace4d4d6d740b724cb56f47c4b414e05fa Mon Sep 17 00:00:00 2001
From: Paul Adedeji <pauladedeji@google.com>
Date: Mon, 06 Jul 2026 17:24:38 -0700
Subject: [PATCH] [ntp footer] Ensure proper navigation context attribution.

Passes explicit source `WebContents` parameters during
`OpenUrlInCurrentTab` navigations from the NTP footer WebUI. This
ensures navigations are properly associated with their attached tab
context.

Change-Id: Idaf35b2b6e120a0303b6e8190bdf53882ba5297a
Bug: b:517395590
Fixed: b:517395590
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8025870
Auto-Submit: Paul Adedeji <pauladedeji@google.com>
Commit-Queue: Riley Tatum <rtatum@google.com>
Reviewed-by: Riley Tatum <rtatum@google.com>
Cr-Commit-Position: refs/heads/main@{#1657594}
---
diff --git a/chrome/browser/ui/views/new_tab_footer/footer_controller.cc b/chrome/browser/ui/views/new_tab_footer/footer_controller.cc
index 6bd39ba..89951e2 100644
--- a/chrome/browser/ui/views/new_tab_footer/footer_controller.cc
+++ b/chrome/browser/ui/views/new_tab_footer/footer_controller.cc
@@ -145,7 +145,7 @@
   const bool show_extension = ShouldShowExtensionFooter(url);
   const bool show = show_managed || show_extension;
   if (show) {
-    footer_->ShowUI(load_start_timestamp, url);
+    footer_->ShowUI(load_start_timestamp, url, web_contents()->GetWeakPtr());
   } else {
     footer_->CloseUI();
   }
diff --git a/chrome/browser/ui/views/new_tab_footer/footer_web_view.cc b/chrome/browser/ui/views/new_tab_footer/footer_web_view.cc
index b43be1c..15246ae 100644
--- a/chrome/browser/ui/views/new_tab_footer/footer_web_view.cc
+++ b/chrome/browser/ui/views/new_tab_footer/footer_web_view.cc
@@ -33,8 +33,12 @@
   contents_wrapper_ = nullptr;
 }
 
-void NewTabFooterWebView::ShowUI(base::TimeTicks load_start, GURL url) {
+void NewTabFooterWebView::ShowUI(
+    base::TimeTicks load_start,
+    GURL url,
+    base::WeakPtr<content::WebContents> attached_tab_contents) {
   attached_tab_url_ = url;
+  attached_tab_contents_ = attached_tab_contents;
   ShowUI();
   base::UmaHistogramMediumTimes("NewTabPage.Footer.ShownTime",
                                 base::TimeTicks::Now() - load_start);
@@ -100,6 +104,18 @@
       event, GetFocusManager());
 }
 
+content::WebContents* NewTabFooterWebView::OpenURLFromTab(
+    content::WebContents* source,
+    const content::OpenURLParams& params,
+    base::OnceCallback<void(content::NavigationHandle&)>
+        navigation_handle_callback) {
+  if (!attached_tab_contents_) {
+    return nullptr;
+  }
+  return attached_tab_contents_->OpenURL(params,
+                                         std::move(navigation_handle_callback));
+}
+
 BEGIN_METADATA(NewTabFooterWebView)
 END_METADATA
 
diff --git a/chrome/browser/ui/views/new_tab_footer/footer_web_view.h b/chrome/browser/ui/views/new_tab_footer/footer_web_view.h
index 8b762ba..78bcf66 100644
--- a/chrome/browser/ui/views/new_tab_footer/footer_web_view.h
+++ b/chrome/browser/ui/views/new_tab_footer/footer_web_view.h
@@ -38,7 +38,9 @@
   NewTabFooterWebView& operator=(const NewTabFooterWebView&) = delete;
   ~NewTabFooterWebView() override;
 
-  void ShowUI(base::TimeTicks load_start, GURL url);
+  void ShowUI(base::TimeTicks load_start,
+              GURL url,
+              base::WeakPtr<content::WebContents> attached_tab_contents);
 
   // WebUIContentsWrapper::Host:
   void ShowUI() override;
@@ -49,12 +51,18 @@
   void HideCustomContextMenu() override;
   bool HandleKeyboardEvent(content::WebContents* source,
                            const input::NativeWebKeyboardEvent& event) override;
+  content::WebContents* OpenURLFromTab(
+      content::WebContents* source,
+      const content::OpenURLParams& params,
+      base::OnceCallback<void(content::NavigationHandle&)>
+          navigation_handle_callback) override;
 
  private:
   // The URL of tab that the footer is attached to.
   // This URL is updated on navigation or tab change when the footer needs to be
   // shown.
   GURL attached_tab_url_;
+  base::WeakPtr<content::WebContents> attached_tab_contents_;
   std::unique_ptr<views::MenuRunner> context_menu_runner_;
   std::unique_ptr<ui::MenuModel> context_menu_model_;
   // Processes keyboard events not handled by the renderer.
diff --git a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc
index e007288..0bf13c0 100644
--- a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc
+++ b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.cc
@@ -184,7 +184,7 @@
   content::OpenURLParams params(url, content::Referrer(),
                                 WindowOpenDisposition::CURRENT_TAB,
                                 ui::PAGE_TRANSITION_LINK, false);
-  browser_window->OpenURL(params, /*navigation_handle_callback=*/{});
+  web_contents_->OpenURL(params, /*navigation_handle_callback=*/{});
 }
 
 std::string NewTabFooterHandler::GetManagementNoticeText() {
diff --git a/chrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc b/chrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc
index be73949b..486728db 100644
--- a/chrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc
+++ b/chrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc
@@ -30,6 +30,7 @@
 #include "components/search/ntp_features.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "extensions/common/extension.h"
 #include "extensions/test/test_extension_dir.h"
 #include "net/base/url_util.h"
@@ -467,3 +468,34 @@
              TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
   EXPECT_FALSE(footer()->GetVisible());
 }
+
+IN_PROC_BROWSER_TEST_F(FooterControllerSplitViewTest, OpenUrlFromTabInSplit) {
+  auto extension = LoadNtpExtension();
+
+  tab_strip_model()->ActivateTabAt(0);
+  NavigateCurrentTab(GURL(extension->url()));
+  content::WebContents* ntp_tab_contents =
+      tab_strip_model()->GetWebContentsAt(0);
+
+  tab_strip_model()->ActivateTabAt(1);
+  content::WebContents* active_tab_contents =
+      tab_strip_model()->GetActiveWebContents();
+  ASSERT_NE(ntp_tab_contents, active_tab_contents);
+
+  auto* ntp_container = BrowserView::GetBrowserViewForBrowser(browser())
+                            ->GetContentsContainerViewFor(ntp_tab_contents);
+  ASSERT_TRUE(ntp_container);
+  auto* ntp_footer = ntp_container->new_tab_footer_view();
+  ASSERT_TRUE(ntp_footer);
+
+  const GURL kTargetUrl("https://www.google.com/");
+  content::OpenURLParams params(kTargetUrl, content::Referrer(),
+                                WindowOpenDisposition::CURRENT_TAB,
+                                ui::PAGE_TRANSITION_LINK, false);
+  content::TestNavigationObserver nav_observer(ntp_tab_contents);
+  ntp_footer->OpenURLFromTab(ntp_footer->GetWebContents(), params, {});
+  nav_observer.Wait();
+
+  EXPECT_EQ(kTargetUrl, ntp_tab_contents->GetLastCommittedURL());
+  EXPECT_EQ(GURL(kNonNtpUrl), active_tab_contents->GetLastCommittedURL());
+}
diff --git a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
index 3d8efbe06..1ae6537 100644
--- a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
+++ b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
@@ -14,13 +14,16 @@
 #include "chrome/browser/extensions/extension_url_overrides.h"
 #include "chrome/browser/search/background/ntp_custom_background_service.h"
 #include "chrome/browser/search/background/ntp_custom_background_service_factory.h"
+#include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h"
 #include "chrome/browser/ui/webui/new_tab_footer/mock_new_tab_footer_document.h"
 #include "chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom.h"
 #include "chrome/browser/ui/webui/top_chrome/top_chrome_web_ui_controller.h"
+#include "chrome/browser/ui/webui/webui_embedding_context.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/themes/ntp_custom_background_service_observer.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "content/public/test/test_web_ui.h"
 #include "extensions/browser/extension_registrar.h"
 #include "extensions/browser/test_extension_registry_observer.h"
@@ -73,6 +76,17 @@
   MOCK_METHOD(void, AddObserver, (NtpCustomBackgroundServiceObserver*));
 };
 
+class MockWebContentsDelegate : public content::WebContentsDelegate {
+ public:
+  MOCK_METHOD(content::WebContents*,
+              OpenURLFromTab,
+              (content::WebContents * source,
+               const content::OpenURLParams& params,
+               base::OnceCallback<void(content::NavigationHandle&)>
+                   navigation_handle_callback),
+              (override));
+};
+
 class NewTabFooterHandlerExtensionTest
     : public extensions::ExtensionServiceTestBase {
  public:
@@ -282,6 +296,40 @@
   testing::Mock::VerifyAndClearExpectations(&document_);
 }
 
+TEST_F(NewTabFooterHandlerExtensionTest, OpenUrlInCurrentTab) {
+  testing::NiceMock<MockBrowserWindowInterface> mock_browser_interface;
+  webui::SetBrowserWindowInterface(web_contents_.get(),
+                                   &mock_browser_interface);
+
+  MockWebContentsDelegate mock_delegate;
+  web_contents_->SetDelegate(&mock_delegate);
+
+  const GURL kTestUrl("https://www.example.com");
+  EXPECT_CALL(
+      mock_delegate,
+      OpenURLFromTab(web_contents_.get(),
+                     testing::Field(&content::OpenURLParams::url, kTestUrl),
+                     testing::_))
+      .WillOnce(testing::Return(nullptr));
+
+  handler().OpenUrlInCurrentTab(kTestUrl);
+}
+
+TEST_F(NewTabFooterHandlerExtensionTest, OpenUrlInCurrentTab_InvalidUrl) {
+  testing::NiceMock<MockBrowserWindowInterface> mock_browser_interface;
+  webui::SetBrowserWindowInterface(web_contents_.get(),
+                                   &mock_browser_interface);
+
+  MockWebContentsDelegate mock_delegate;
+  web_contents_->SetDelegate(&mock_delegate);
+
+  const GURL kInvalidUrl("https://");
+  EXPECT_CALL(mock_delegate, OpenURLFromTab(testing::_, testing::_, testing::_))
+      .Times(0);
+
+  handler().OpenUrlInCurrentTab(kInvalidUrl);
+}
+
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
 class NewTabFooterHandlerEnterpriseTest : public testing::Test {
  public:
diff --git a/chrome/browser/ui/webui/new_tab_footer/BUILD.gn b/chrome/browser/ui/webui/new_tab_footer/BUILD.gn
index d58eaad..1d980eca 100644
--- a/chrome/browser/ui/webui/new_tab_footer/BUILD.gn
+++ b/chrome/browser/ui/webui/new_tab_footer/BUILD.gn
@@ -101,6 +101,7 @@
   deps = [
     ":test_support",
     "//chrome/browser/enterprise/browser_management:management_identity",
+    "//chrome/browser/ui/webui:webui_util",
     "//components/themes",
   ]
 }
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc b/chrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc
index be73949b..486728db 100644
--- a/chrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc
+++ b/chrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc
@@ -30,6 +30,7 @@
 #include "components/search/ntp_features.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "extensions/common/extension.h"
 #include "extensions/test/test_extension_dir.h"
 #include "net/base/url_util.h"
@@ -467,3 +468,34 @@
              TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
   EXPECT_FALSE(footer()->GetVisible());
 }
+
+IN_PROC_BROWSER_TEST_F(FooterControllerSplitViewTest, OpenUrlFromTabInSplit) {
+  auto extension = LoadNtpExtension();
+
+  tab_strip_model()->ActivateTabAt(0);
+  NavigateCurrentTab(GURL(extension->url()));
+  content::WebContents* ntp_tab_contents =
+      tab_strip_model()->GetWebContentsAt(0);
+
+  tab_strip_model()->ActivateTabAt(1);
+  content::WebContents* active_tab_contents =
+      tab_strip_model()->GetActiveWebContents();
+  ASSERT_NE(ntp_tab_contents, active_tab_contents);
+
+  auto* ntp_container = BrowserView::GetBrowserViewForBrowser(browser())
+                            ->GetContentsContainerViewFor(ntp_tab_contents);
+  ASSERT_TRUE(ntp_container);
+  auto* ntp_footer = ntp_container->new_tab_footer_view();
+  ASSERT_TRUE(ntp_footer);
+
+  const GURL kTargetUrl("https://www.google.com/");
+  content::OpenURLParams params(kTargetUrl, content::Referrer(),
+                                WindowOpenDisposition::CURRENT_TAB,
+                                ui::PAGE_TRANSITION_LINK, false);
+  content::TestNavigationObserver nav_observer(ntp_tab_contents);
+  ntp_footer->OpenURLFromTab(ntp_footer->GetWebContents(), params, {});
+  nav_observer.Wait();
+
+  EXPECT_EQ(kTargetUrl, ntp_tab_contents->GetLastCommittedURL());
+  EXPECT_EQ(GURL(kNonNtpUrl), active_tab_contents->GetLastCommittedURL());
+}
diff --git a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
index 3d8efbe06..1ae6537 100644
--- a/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
+++ b/chrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
@@ -14,13 +14,16 @@
 #include "chrome/browser/extensions/extension_url_overrides.h"
 #include "chrome/browser/search/background/ntp_custom_background_service.h"
 #include "chrome/browser/search/background/ntp_custom_background_service_factory.h"
+#include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h"
 #include "chrome/browser/ui/webui/new_tab_footer/mock_new_tab_footer_document.h"
 #include "chrome/browser/ui/webui/new_tab_footer/new_tab_footer.mojom.h"
 #include "chrome/browser/ui/webui/top_chrome/top_chrome_web_ui_controller.h"
+#include "chrome/browser/ui/webui/webui_embedding_context.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/themes/ntp_custom_background_service_observer.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "content/public/test/test_web_ui.h"
 #include "extensions/browser/extension_registrar.h"
 #include "extensions/browser/test_extension_registry_observer.h"
@@ -73,6 +76,17 @@
   MOCK_METHOD(void, AddObserver, (NtpCustomBackgroundServiceObserver*));
 };
 
+class MockWebContentsDelegate : public content::WebContentsDelegate {
+ public:
+  MOCK_METHOD(content::WebContents*,
+              OpenURLFromTab,
+              (content::WebContents * source,
+               const content::OpenURLParams& params,
+               base::OnceCallback<void(content::NavigationHandle&)>
+                   navigation_handle_callback),
+              (override));
+};
+
 class NewTabFooterHandlerExtensionTest
     : public extensions::ExtensionServiceTestBase {
  public:
@@ -282,6 +296,40 @@
   testing::Mock::VerifyAndClearExpectations(&document_);
 }
 
+TEST_F(NewTabFooterHandlerExtensionTest, OpenUrlInCurrentTab) {
+  testing::NiceMock<MockBrowserWindowInterface> mock_browser_interface;
+  webui::SetBrowserWindowInterface(web_contents_.get(),
+                                   &mock_browser_interface);
+
+  MockWebContentsDelegate mock_delegate;
+  web_contents_->SetDelegate(&mock_delegate);
+
+  const GURL kTestUrl("https://www.example.com");
+  EXPECT_CALL(
+      mock_delegate,
+      OpenURLFromTab(web_contents_.get(),
+                     testing::Field(&content::OpenURLParams::url, kTestUrl),
+                     testing::_))
+      .WillOnce(testing::Return(nullptr));
+
+  handler().OpenUrlInCurrentTab(kTestUrl);
+}
+
+TEST_F(NewTabFooterHandlerExtensionTest, OpenUrlInCurrentTab_InvalidUrl) {
+  testing::NiceMock<MockBrowserWindowInterface> mock_browser_interface;
+  webui::SetBrowserWindowInterface(web_contents_.get(),
+                                   &mock_browser_interface);
+
+  MockWebContentsDelegate mock_delegate;
+  web_contents_->SetDelegate(&mock_delegate);
+
+  const GURL kInvalidUrl("https://");
+  EXPECT_CALL(mock_delegate, OpenURLFromTab(testing::_, testing::_, testing::_))
+      .Times(0);
+
+  handler().OpenUrlInCurrentTab(kInvalidUrl);
+}
+
 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
 class NewTabFooterHandlerEnterpriseTest : public testing::Test {
  public:
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.