Medium chrome Memory Corruption 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMemory corruption in Omnibox
DescriptionMemory corruption in Omnibox
ComponentOmnibox
Bug ClassMemory Corruption
Tracker517407917
Fix commitb64675fd64d4 (chromium/src) +109/-7
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-20

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
modified
if
chrome/browser/ui/views/toolbar/toolbar_view.cc
modified
SecurityStateWaiter
chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
modified
if
chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
modified
CustomTabBarViewBrowserTest
chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
modified

Files Changed

  • chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
  • chrome/browser/ui/views/toolbar/toolbar_view.cc
  • chrome/browser/ui/views/location_bar/custom_tab_bar_view.h
  • chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
From b64675fd64d47caa50fec2b065e6352f391a39f2 Mon Sep 17 00:00:00 2001
From: Nate Chapin <[email protected]>
Date: Mon, 21 Sep 2026 12:29:24 -0700
Subject: [PATCH] Update CustomTabBarView when visible page state changes dynamically

When a Progressive Web App window is displayed in custom tab mode,
dynamic in-place status updates on an already visible custom tab bar did
not refresh `CustomTabBarView`. Consequently, `LocationIconView` and
related UI elements remained out of sync with the current `WebContents`
state.

This CL adds state change verification to `CustomTabBarView` and ensures
`ToolbarView` triggers `UpdateContents()` when the visible page state
changes. It also adds a null check for the visible navigation entry when
updating the title.

TAG=agy

Fixed: 517407917
Change-Id: Id5e838d6a5cf62673e4cec4f77fc3ea3897db9bb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8422705
Commit-Queue: Nate Chapin <[email protected]>
Reviewed-by: Allen Bauer <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1701963}
---
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
index 5f581da..35b4ef5 100644
--- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
@@ -348,6 +348,11 @@
   }
 }
 
+bool CustomTabBarView::HasSecurityStateChanged() const {
+  return GetVisible() && location_icon_view_ &&
+         location_icon_view_->HasSecurityStateChanged();
+}
+
 void CustomTabBarView::UpdateContents() {
   // If the toolbar should not be shown don't update the UI, as the toolbar may
   // be animating out and it looks messy.
@@ -364,8 +369,10 @@
 
   content::NavigationEntry* entry = contents->GetController().GetVisibleEntry();
   std::u16string title, location;
-  title = WindowMetadataController::FormatTitleForDisplay(
-      entry->GetTitleForDisplay());
+  if (entry) {
+    title = WindowMetadataController::FormatTitleForDisplay(
+        entry->GetTitleForDisplay());
+  }
   if (ShouldDisplayUrl(contents)) {
     location = web_app::AppBrowserController::FormatUrlOrigin(
         contents->GetVisibleURL(), url_formatter::kFormatUrlOmitDefaults);
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.h b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.h
index f1adede..f0a534a 100644
--- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.h
+++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.h
@@ -54,6 +54,13 @@
 
   LocationIconView* location_icon_view() { return location_icon_view_; }
 
+  // Returns true if the custom tab bar's security state does not match
+  // the currently visible state.
+  bool HasSecurityStateChanged() const;
+
+  // Populates child elements with page details from the current WebContents.
+  void UpdateContents();
+
   // views::AccessiblePaneView:
   gfx::Rect GetAnchorBoundsInScreen() const override;
   void SetVisible(bool visible) override;
@@ -123,9 +130,6 @@
     return web_app::AppBrowserController::From(browser_);
   }
 
-  // Populates child elements with page details from the current WebContents.
-  void UpdateContents();
-
   bool GetShowTitle() const;
 
   SkColor title_bar_color_ = SK_ColorTRANSPARENT;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 2853c5c4..67f28a8 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -1175,7 +1175,9 @@
 }
 
 void ToolbarView::Update(WebContents* tab) {
-  if (location_bar_) {
+  if (custom_tab_bar_) {
+    custom_tab_bar_->UpdateContents();
+  } else if (location_bar_) {
     location_bar_->Update(tab);
   }
 
@@ -1194,7 +1196,12 @@
 }
 
 bool ToolbarView::UpdateSecurityState() {
-  if (location_bar_ && location_bar_->HasSecurityStateChanged()) {
+  const bool has_security_state_changed =
+      display_mode_ == DisplayMode::kCustomTab
+          ? (custom_tab_bar_ && custom_tab_bar_->HasSecurityStateChanged())
+          : (location_bar_ && location_bar_->HasSecurityStateChanged());
+
+  if (has_security_state_changed) {
     Update(nullptr);
     return true;
   }
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc b/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
index 56fd97e..202ed937 100644
--- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
@@ -23,14 +23,17 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/security_interstitials/content/security_interstitial_controller_client.h"
 #include "components/security_interstitials/content/security_interstitial_page.h"
 #include "components/security_interstitials/content/security_interstitial_tab_helper.h"
 #include "components/security_interstitials/content/settings_page_helper.h"
 #include "components/security_interstitials/core/metrics_helper.h"
+#include "components/security_state/core/security_state.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_mock_cert_verifier.h"
@@ -180,6 +183,29 @@
   bool install_interstitial_ = true;
 };
 
+// Runs the message loop until WebContents::DidChangeVisibleSecurityState fires
+// at least once.
+class SecurityStateWaiter : public content::WebContentsObserver {
+ public:
+  explicit SecurityStateWaiter(content::WebContents* contents)
+      : content::WebContentsObserver(contents) {}
+  void DidChangeVisibleSecurityState() override {
+    fired_ = true;
+    if (run_loop_.running()) {
+      run_loop_.Quit();
+    }
+  }
+  void Wait() {
+    if (!fired_) {
+      run_loop_.Run();
+    }
+  }
+
+ private:
+  bool fired_ = false;
+  base::RunLoop run_loop_;
+};
+
 }  // namespace
 
 class CustomTabBarViewBrowserTest : public web_app::WebAppBrowserTestBase {
@@ -750,3 +776,61 @@
           u"/",
       base::ASCIIToUTF16(embedded_https_test_server().GetURL("/").spec()));
 }
+
+// Check that the CustomTabBarView security chip updates when the visible
+// security state changes while the bar is already visible.
+IN_PROC_BROWSER_TEST_F(CustomTabBarViewBrowserTest,
+                       SecurityChipUpdatesOnVisibleSecurityStateChange) {
+  const GURL app_url =
+      embedded_https_test_server().GetURL("app.com", "/ssl/google.html");
+  InstallPWA(app_url);
+  ASSERT_TRUE(app_browser_);
+  EXPECT_EQ(app_browser_->GetType(), BrowserWindowInterface::Type::TYPE_APP);
+
+  BrowserView* app_view = BrowserView::GetBrowserViewForBrowser(app_browser_);
+  CustomTabBarView* bar = app_view->toolbar()->custom_tab_bar();
+  ASSERT_TRUE(bar);
+  content::WebContents* contents = app_view->GetActiveWebContents();
+
+  // In-scope: custom tab bar is not shown.
+  EXPECT_FALSE(app_controller_->ShouldShowCustomTabBar());
+  EXPECT_FALSE(bar->GetVisible());
+
+  // Navigate off-scope to a secure HTTPS page. Custom tab bar becomes visible.
+  const GURL offscope_url = embedded_https_test_server().GetURL(
+      "example.com", "/ssl/blank_page.html");
+  NavigateAndWait(contents, offscope_url);
+
+  EXPECT_TRUE(app_controller_->ShouldShowCustomTabBar());
+  EXPECT_TRUE(bar->GetVisible());
+
+  LocationIconView* icon = bar->location_icon_view();
+  ASSERT_TRUE(icon);
+
+  // Baseline: model says SECURE, and displayed chip is in sync.
+  EXPECT_EQ(security_state::SECURE,
+            bar->GetLocationBarModel()->GetSecurityLevel());
+  EXPECT_FALSE(icon->HasSecurityStateChanged());
+  EXPECT_TRUE(icon->GetText().empty());
+  EXPECT_FALSE(icon->ShouldShowLabel());
+  EXPECT_FALSE(app_view->UpdateToolbarSecurityState());
+
+  // Trigger a visible security state change by loading mixed content.
+  SecurityStateWaiter sec_waiter(contents);
+  EXPECT_TRUE(content::ExecJs(contents, R"(
+      let img = document.createElement('img');
+      img.src = 'http://sample-image.test/img.png';
+      document.body.appendChild(img);
+    )"));
+  sec_waiter.Wait();
+
+  // The model now reports a non-SECURE security level.
+  const security_state::SecurityLevel new_level =
+      bar->GetLocationBarModel()->GetSecurityLevel();
+  EXPECT_NE(security_state::SECURE, new_level);
+
+  // The custom tab bar chip should update and remain in sync with the model.
+  EXPECT_FALSE(icon->HasSecurityStateChanged());
+  EXPECT_EQ(icon->GetShowText(), icon->ShouldShowLabel());
+  EXPECT_FALSE(app_view->UpdateToolbarSecurityState());
+}
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc b/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
index 56fd97e..202ed937 100644
--- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view_browsertest.cc
@@ -23,14 +23,17 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/omnibox/browser/location_bar_model.h"
 #include "components/security_interstitials/content/security_interstitial_controller_client.h"
 #include "components/security_interstitials/content/security_interstitial_page.h"
 #include "components/security_interstitials/content/security_interstitial_tab_helper.h"
 #include "components/security_interstitials/content/settings_page_helper.h"
 #include "components/security_interstitials/core/metrics_helper.h"
+#include "components/security_state/core/security_state.h"
 #include "content/public/browser/navigation_controller.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/web_contents_observer.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/content_mock_cert_verifier.h"
@@ -180,6 +183,29 @@
   bool install_interstitial_ = true;
 };
 
+// Runs the message loop until WebContents::DidChangeVisibleSecurityState fires
+// at least once.
+class SecurityStateWaiter : public content::WebContentsObserver {
+ public:
+  explicit SecurityStateWaiter(content::WebContents* contents)
+      : content::WebContentsObserver(contents) {}
+  void DidChangeVisibleSecurityState() override {
+    fired_ = true;
+    if (run_loop_.running()) {
+      run_loop_.Quit();
+    }
+  }
+  void Wait() {
+    if (!fired_) {
+      run_loop_.Run();
+    }
+  }
+
+ private:
+  bool fired_ = false;
+  base::RunLoop run_loop_;
+};
+
 }  // namespace
 
 class CustomTabBarViewBrowserTest : public web_app::WebAppBrowserTestBase {
@@ -750,3 +776,61 @@
           u"/",
       base::ASCIIToUTF16(embedded_https_test_server().GetURL("/").spec()));
 }
+
+// Check that the CustomTabBarView security chip updates when the visible
+// security state changes while the bar is already visible.
+IN_PROC_BROWSER_TEST_F(CustomTabBarViewBrowserTest,
+                       SecurityChipUpdatesOnVisibleSecurityStateChange) {
+  const GURL app_url =
+      embedded_https_test_server().GetURL("app.com", "/ssl/google.html");
+  InstallPWA(app_url);
+  ASSERT_TRUE(app_browser_);
+  EXPECT_EQ(app_browser_->GetType(), BrowserWindowInterface::Type::TYPE_APP);
+
+  BrowserView* app_view = BrowserView::GetBrowserViewForBrowser(app_browser_);
+  CustomTabBarView* bar = app_view->toolbar()->custom_tab_bar();
+  ASSERT_TRUE(bar);
+  content::WebContents* contents = app_view->GetActiveWebContents();
+
+  // In-scope: custom tab bar is not shown.
+  EXPECT_FALSE(app_controller_->ShouldShowCustomTabBar());
+  EXPECT_FALSE(bar->GetVisible());
+
+  // Navigate off-scope to a secure HTTPS page. Custom tab bar becomes visible.
+  const GURL offscope_url = embedded_https_test_server().GetURL(
+      "example.com", "/ssl/blank_page.html");
+  NavigateAndWait(contents, offscope_url);
+
+  EXPECT_TRUE(app_controller_->ShouldShowCustomTabBar());
+  EXPECT_TRUE(bar->GetVisible());
+
+  LocationIconView* icon = bar->location_icon_view();
+  ASSERT_TRUE(icon);
+
+  // Baseline: model says SECURE, and displayed chip is in sync.
+  EXPECT_EQ(security_state::SECURE,
+            bar->GetLocationBarModel()->GetSecurityLevel());
+  EXPECT_FALSE(icon->HasSecurityStateChanged());
+  EXPECT_TRUE(icon->GetText().empty());
+  EXPECT_FALSE(icon->ShouldShowLabel());
+  EXPECT_FALSE(app_view->UpdateToolbarSecurityState());
+
+  // Trigger a visible security state change by loading mixed content.
+  SecurityStateWaiter sec_waiter(contents);
+  EXPECT_TRUE(content::ExecJs(contents, R"(
+      let img = document.createElement('img');
+      img.src = 'http://sample-image.test/img.png';
+      document.body.appendChild(img);
+    )"));
+  sec_waiter.Wait();
+
+  // The model now reports a non-SECURE security level.
+  const security_state::SecurityLevel new_level =
+      bar->GetLocationBarModel()->GetSecurityLevel();
+  EXPECT_NE(security_state::SECURE, new_level);
+
+  // The custom tab bar chip should update and remain in sync with the model.
+  EXPECT_FALSE(icon->HasSecurityStateChanged());
+  EXPECT_EQ(icon->GetShowText(), icon->ShouldShowLabel());
+  EXPECT_FALSE(app_view->UpdateToolbarSecurityState());
+}
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.