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 <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_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