Chrome · NTP Footer
CVE-2026-79123
Logic Error in NTP Footer
Overview
Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/browser/ui/views/new_tab_footer/footer_controller.cc |
modified | |
IN_PROC_BROWSER_TEST_Fchrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.cc |
modified | |
ifchrome/browser/ui/views/new_tab_footer/footer_web_view.cc |
modified |
Files Changed
chrome/browser/ui/views/new_tab_footer/footer_controller.ccchrome/browser/ui/views/new_tab_footer/footer_controller_browsertest.ccchrome/browser/ui/views/new_tab_footer/footer_web_view.ccchrome/browser/ui/views/new_tab_footer/footer_web_view.hchrome/browser/ui/webui/new_tab_footer/BUILD.gnchrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler.ccchrome/browser/ui/webui/new_tab_footer/new_tab_footer_handler_unittest.cc
Patch
From 3bad81ace4d4d6d740b724cb56f47c4b414e05fa Mon Sep 17 00:00:00 2001 From: Paul Adedeji <[email protected]> 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 <[email protected]> Commit-Queue: Riley Tatum <[email protected]> Reviewed-by: Riley Tatum <[email protected]> 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_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/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/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", ] } 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/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*)); };
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.
References
On This Page