Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactIncorrect security UI in Tab Hover Cards
DescriptionIncorrect security UI in Tab Hover Cards
ComponentTab Hover Cards
Bug ClassLogic Error
Tracker448421954
Fix commitcb262a7368ab (chromium/src) +82/-1
CISA KEVNot listed
CreditedHafiizh
Disclosed2026-06-02

Changed Functions

FunctionChangeNotes
if
chrome/browser/ui/views/tabs/hovercard/fade_label_view.cc
modified
if
chrome/browser/ui/views/tabs/hovercard/hover_card_anchor_target.cc
modified
TabHoverCardBubbleViewTest
chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc
modified
TEST_F
chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc
modified
TEST_F
ui/views/controls/label_unittest.cc
modified

Files Changed

  • chrome/browser/ui/views/tabs/hovercard/fade_label_view.cc
  • chrome/browser/ui/views/tabs/hovercard/fade_label_view.h
  • chrome/browser/ui/views/tabs/hovercard/hover_card_anchor_target.cc
  • chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc
  • ui/views/controls/label.cc
  • ui/views/controls/label.h
  • ui/views/controls/label_unittest.cc
From cb262a7368abf1bab2ebbd122e2f8eabc4bc4066 Mon Sep 17 00:00:00 2001
From: Alison Gale <[email protected]>
Date: Tue, 14 Apr 2026 14:28:05 -0700
Subject: [PATCH] [Hovercards] Use the correct directionality for hovercard domains

Relevant documentation:
https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/url_display_guidelines/url_display_guidelines.md#rtl

Screenshot: https://screenshot.googleplex.com/AGAkRJEPEq9DzEn

Note that the title of the page is the opposite direction but titles
aren't urls so that should be okay.

Bug: 448421954
Change-Id: If556b49e0764c6f73edebeb490d3c4b0c5dccb41
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7762370
Reviewed-by: David Yeung <[email protected]>
Commit-Queue: Alison Gale <[email protected]>
Reviewed-by: Eshwar Stalin <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1614711}
---

diff --git a/chrome/browser/ui/views/tabs/hovercard/fade_label_view.cc b/chrome/browser/ui/views/tabs/hovercard/fade_label_view.cc
index cfebb56..922a881 100644
--- a/chrome/browser/ui/views/tabs/hovercard/fade_label_view.cc
+++ b/chrome/browser/ui/views/tabs/hovercard/fade_label_view.cc
@@ -24,6 +24,9 @@
   std::u16string text = data.text;
   const bool is_filename = data.is_filename;
   SetElideBehavior(is_filename ? gfx::NO_ELIDE : data.elide);
+  SetDirectionalityMode(
+      data.is_domain_url ? gfx::DirectionalityMode::DIRECTIONALITY_AS_URL
+                         : gfx::DirectionalityMode::DIRECTIONALITY_FROM_TEXT);
   if (is_filename) {
     text = TruncateFilenameToTwoLines(text);
   }
diff --git a/chrome/browser/ui/views/tabs/hovercard/fade_label_view.h b/chrome/browser/ui/views/tabs/hovercard/fade_label_view.h
index e3f14e56..f440008 100644
--- a/chrome/browser/ui/views/tabs/hovercard/fade_label_view.h
+++ b/chrome/browser/ui/views/tabs/hovercard/fade_label_view.h
@@ -18,6 +18,7 @@
   std::u16string text;
   bool is_filename = false;
   gfx::ElideBehavior elide = gfx::ELIDE_TAIL;
+  bool is_domain_url = false;
 };
 
 using FadeWrapper_Label_FadeLabelViewData =
diff --git a/chrome/browser/ui/views/tabs/hovercard/hover_card_anchor_target.cc b/chrome/browser/ui/views/tabs/hovercard/hover_card_anchor_target.cc
index d571b8b3..ae25d69 100644
--- a/chrome/browser/ui/views/tabs/hovercard/hover_card_anchor_target.cc
+++ b/chrome/browser/ui/views/tabs/hovercard/hover_card_anchor_target.cc
@@ -96,6 +96,7 @@
   }
 
   std::u16string domain;
+  bool is_domain_url = false;
   if (domain_url.SchemeIsFile()) {
     domain = l10n_util::GetStringUTF16(IDS_HOVER_CARD_FILE_URL_SOURCE);
   } else if (domain_url.SchemeIsBlob()) {
@@ -104,6 +105,7 @@
     domain = l10n_util::GetStringUTF16(IDS_HOVER_CARD_VIEW_SOURCE_URL_SOURCE);
   } else {
     if (tab_data.should_display_url) {
+      is_domain_url = true;
       // Hide the domain when necessary. This leaves an empty space in the
       // card, but this scenario is very rare. Also, shrinking the card to
       // remove the space would result in visual noise, so we keep it simple.
@@ -121,7 +123,7 @@
 
   card_data.thumbnail = tab_data.thumbnail;
   card_data.title_data = GetTabTitleLabel(tab_data);
-  card_data.domain_data = {domain, false, gfx::ELIDE_HEAD};
+  card_data.domain_data = {domain, false, gfx::ELIDE_HEAD, is_domain_url};
 
   // Now set the collaboration data.
   using collaboration::messaging::CollaborationEvent;
diff --git a/chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc b/chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc
index f9aea07..c4e581a 100644
--- a/chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc
@@ -9,13 +9,19 @@
 
 #include "base/logging.h"
 #include "build/build_config.h"
+#include "chrome/browser/ui/tabs/tab_data.h"
+#include "chrome/browser/ui/views/tabs/fake_tab_slot_controller.h"
 #include "chrome/browser/ui/views/tabs/hovercard/filename_elider.h"
+#include "chrome/browser/ui/views/tabs/hovercard/hover_card_anchor_target.h"
+#include "chrome/browser/ui/views/tabs/tab.h"
+#include "chrome/test/views/chrome_views_test_base.h"
 #include "content/public/test/browser_task_environment.h"
 #include "skia/ext/font_utils.h"
 #include "testing/gtest/include/gtest/gtest-param-test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/render_text.h"
+#include "ui/views/widget/widget.h"
 
 #if BUILDFLAG(IS_MAC)
 #include "base/mac/mac_util.h"
@@ -374,3 +380,40 @@
   const FindImageDimensionsTestParams& params = GetParam();
   EXPECT_EQ(params.expected, FilenameElider::FindImageDimensions(params.text));
 }
+
+class TabHoverCardBubbleViewTest : public ChromeViewsTestBase {
+ public:
+  TabHoverCardBubbleViewTest() = default;
+  ~TabHoverCardBubbleViewTest() override = default;
+};
+
+TEST_F(TabHoverCardBubbleViewTest, HoverCardLabel_DomainIsUrl) {
+  auto tab_slot_controller = std::make_unique<FakeTabSlotController>();
+  std::unique_ptr<views::Widget> widget =
+      CreateTestWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET);
+  Tab* tab = widget->SetContentsView(
+      std::make_unique<Tab>(tabs::TabHandle(1), tab_slot_controller.get()));
+
+  TabHoverCardBubbleView* hover_card =
+      new TabHoverCardBubbleView(tab, {.show_domain = true});
+
+  tabs::TabData data;
+  data.last_committed_url = GURL("https://example.com");
+  data.should_display_url = true;
+  tab->SetDataForTesting(data);
+
+  hover_card->UpdateCardContent(tab);
+
+  FadeLabelView* domain_view = hover_card->GetDomainViewForTesting();
+  FadeLabel* primary_label = domain_view->GetPrimaryViewForTesting();
+  EXPECT_EQ(gfx::DirectionalityMode::DIRECTIONALITY_AS_URL,
+            primary_label->GetDirectionalityMode());
+
+  data.should_display_url = false;
+  tab->SetDataForTesting(data);
+  hover_card->UpdateCardContent(tab);
+  EXPECT_EQ(gfx::DirectionalityMode::DIRECTIONALITY_FROM_TEXT,
+            primary_label->GetDirectionalityMode());
+
+  hover_card->GetWidget()->CloseNow();
+}
diff --git a/ui/views/controls/label.cc b/ui/views/controls/label.cc
index ac350ea7..cf0139f 100644
--- a/ui/views/controls/label.cc
+++ b/ui/views/controls/label.cc
@@ -536,6 +536,14 @@
   OnDisplayTextTruncation();
 }
 
+void Label::SetDirectionalityMode(gfx::DirectionalityMode mode) {
+  full_text_->SetDirectionalityMode(mode);
+}
+
+gfx::DirectionalityMode Label::GetDirectionalityMode() const {
+  return full_text_->directionality_mode();
+}
+
 void Label::SetCustomTooltipText(std::u16string_view tooltip_text) {
   custom_tooltip_text_ = std::u16string(tooltip_text);
 
diff --git a/ui/views/controls/label.h b/ui/views/controls/label.h
index 0d89a9cd..b1ccc70 100644
--- a/ui/views/controls/label.h
+++ b/ui/views/controls/label.h
@@ -241,6 +241,10 @@
   gfx::ElideBehavior GetElideBehavior() const;
   void SetElideBehavior(gfx::ElideBehavior elide_behavior);
 
+  // Sets the directionality mode of the label.
+  void SetDirectionalityMode(gfx::DirectionalityMode mode);
+  gfx::DirectionalityMode GetDirectionalityMode() const;
+
   // Sets the custom local tooltip text.  Default behavior for a label
   // (single-line) is to show the full text if it is wider than its bounds.
   // Calling this overrides the default behavior and lets you set a custom
diff --git a/ui/views/controls/label_unittest.cc b/ui/views/controls/label_unittest.cc
index 8cbbb3e..5eaabc2 100644
--- a/ui/views/controls/label_unittest.cc
+++ b/ui/views/controls/label_unittest.cc
@@ -1255,6 +1255,26 @@
             ltr_text_force_rtl.GetTextDirectionForTesting());
 }
 
+TEST_F(LabelTest, SetDirectionalityMode) {
+  Label label(ToRTL("0123456"));
+  EXPECT_EQ(base::i18n::TextDirection::RIGHT_TO_LEFT,
+            label.GetTextDirectionForTesting());
+
+  label.SetDirectionalityMode(
+      gfx::DirectionalityMode::DIRECTIONALITY_FORCE_LTR);
+  EXPECT_EQ(base::i18n::TextDirection::LEFT_TO_RIGHT,
+            label.GetTextDirectionForTesting());
+
+  label.SetDirectionalityMode(
+      gfx::DirectionalityMode::DIRECTIONALITY_FORCE_RTL);
+  EXPECT_EQ(base::i18n::TextDirection::RIGHT_TO_LEFT,
+            label.GetTextDirectionForTesting());
+
+  label.SetDirectionalityMode(gfx::DirectionalityMode::DIRECTIONALITY_AS_URL);
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc b/chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc
index f9aea07..c4e581a 100644
--- a/chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/tabs/hovercard/tab_hover_card_bubble_view_unittest.cc
@@ -9,13 +9,19 @@
 
 #include "base/logging.h"
 #include "build/build_config.h"
+#include "chrome/browser/ui/tabs/tab_data.h"
+#include "chrome/browser/ui/views/tabs/fake_tab_slot_controller.h"
 #include "chrome/browser/ui/views/tabs/hovercard/filename_elider.h"
+#include "chrome/browser/ui/views/tabs/hovercard/hover_card_anchor_target.h"
+#include "chrome/browser/ui/views/tabs/tab.h"
+#include "chrome/test/views/chrome_views_test_base.h"
 #include "content/public/test/browser_task_environment.h"
 #include "skia/ext/font_utils.h"
 #include "testing/gtest/include/gtest/gtest-param-test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/render_text.h"
+#include "ui/views/widget/widget.h"
 
 #if BUILDFLAG(IS_MAC)
 #include "base/mac/mac_util.h"
@@ -374,3 +380,40 @@
   const FindImageDimensionsTestParams& params = GetParam();
   EXPECT_EQ(params.expected, FilenameElider::FindImageDimensions(params.text));
 }
+
+class TabHoverCardBubbleViewTest : public ChromeViewsTestBase {
+ public:
+  TabHoverCardBubbleViewTest() = default;
+  ~TabHoverCardBubbleViewTest() override = default;
+};
+
+TEST_F(TabHoverCardBubbleViewTest, HoverCardLabel_DomainIsUrl) {
+  auto tab_slot_controller = std::make_unique<FakeTabSlotController>();
+  std::unique_ptr<views::Widget> widget =
+      CreateTestWidget(views::Widget::InitParams::CLIENT_OWNS_WIDGET);
+  Tab* tab = widget->SetContentsView(
+      std::make_unique<Tab>(tabs::TabHandle(1), tab_slot_controller.get()));
+
+  TabHoverCardBubbleView* hover_card =
+      new TabHoverCardBubbleView(tab, {.show_domain = true});
+
+  tabs::TabData data;
+  data.last_committed_url = GURL("https://example.com");
+  data.should_display_url = true;
+  tab->SetDataForTesting(data);
+
+  hover_card->UpdateCardContent(tab);
+
+  FadeLabelView* domain_view = hover_card->GetDomainViewForTesting();
+  FadeLabel* primary_label = domain_view->GetPrimaryViewForTesting();
+  EXPECT_EQ(gfx::DirectionalityMode::DIRECTIONALITY_AS_URL,
+            primary_label->GetDirectionalityMode());
+
+  data.should_display_url = false;
+  tab->SetDataForTesting(data);
+  hover_card->UpdateCardContent(tab);
+  EXPECT_EQ(gfx::DirectionalityMode::DIRECTIONALITY_FROM_TEXT,
+            primary_label->GetDirectionalityMode());
+
+  hover_card->GetWidget()->CloseNow();
+}
diff --git a/ui/views/controls/label_unittest.cc b/ui/views/controls/label_unittest.cc
index 8cbbb3e..5eaabc2 100644
--- a/ui/views/controls/label_unittest.cc
+++ b/ui/views/controls/label_unittest.cc
@@ -1255,6 +1255,26 @@
             ltr_text_force_rtl.GetTextDirectionForTesting());
 }
 
+TEST_F(LabelTest, SetDirectionalityMode) {
+  Label label(ToRTL("0123456"));
+  EXPECT_EQ(base::i18n::TextDirection::RIGHT_TO_LEFT,
+            label.GetTextDirectionForTesting());
+
+  label.SetDirectionalityMode(
+      gfx::DirectionalityMode::DIRECTIONALITY_FORCE_LTR);
+  EXPECT_EQ(base::i18n::TextDirection::LEFT_TO_RIGHT,
+            label.GetTextDirectionForTesting());
+
+  label.SetDirectionalityMode(
+      gfx::DirectionalityMode::DIRECTIONALITY_FORCE_RTL);
+  EXPECT_EQ(base::i18n::TextDirection::RIGHT_TO_LEFT,
+            label.GetTextDirectionForTesting());
+
+  label.SetDirectionalityMode(gfx::DirectionalityMode::DIRECTIONALITY_AS_URL);
+  EXPECT_EQ(base::i18n::TextDirection::LEFT_TO_RIGHT,
+            label.GetTextDirectionForTesting());
+}
+
 TEST_F(LabelTest, DefaultDirectionalityIsFromText) {
   Label ltr(u"Foo");
   EXPECT_EQ(base::i18n::TextDirection::LEFT_TO_RIGHT,
Loading diff…

Original Bug Report

reported by [email protected]

Tab hovercard doesn't show the origin correctly

VULNERABILITY DETAILS This vulnerability is similar to this one: https://issues.chromium.org/issues/40075024 but in this bug Popup window tab doesn’t show correctly. in the popup window it shows https://pwr.wtf.کورد/ which should be https://کورد.pwr.wtf/

VERSION Chrome Version 142.0.7444.0 (Official Build) canary (64-bit) Operating System: Windows 11

REPRODUCTION CASE

  1. Go to https://کورد.pwr.wtf/poc.html?
  2. Hover over the tab
View on issue tracker