Medium firefox Spoofing 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionSpoofing issue in the Toolbar component in Firefox for Android
ComponentCore
Bug ClassSpoofing
Tracker2018513
Fix commitaa18978e5e7e (firefox) +56/-28
CISA KEVNot listed
Creditedyfbug123
Disclosed2026-05-19

Files Changed

  • mobile/android/android-components/components/compose/browser-toolbar/src/main/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrl.kt
  • mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrlTest.kt
diff --git a/mobile/android/android-components/components/compose/browser-toolbar/src/main/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrl.kt b/mobile/android/android-components/components/compose/browser-toolbar/src/main/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrl.kt
index 7ceb0b6d3ea..5e7c5fefad1 100644
--- a/mobile/android/android-components/components/compose/browser-toolbar/src/main/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrl.kt
+++ b/mobile/android/android-components/components/compose/browser-toolbar/src/main/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrl.kt
@@ -27,6 +27,7 @@ import androidx.compose.ui.draw.drawWithContent
 import androidx.compose.ui.graphics.BlendMode
 import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.SolidColor
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.layout.onSizeChanged
 import androidx.compose.ui.platform.LocalDensity
@@ -171,7 +172,12 @@ private fun Modifier.focusTextIndexRange(
                     .drawWithContent {
                         drawContent()
 
-                        val brush = createDomainHighlightBrush(text, highlightRange, scrollState.value, fadeFraction)
+                        val brush = createUrlFadeBrush(
+                            scrolledPixels = scrollState.value,
+                            maxScrollPixels = scrollState.maxValue,
+                            viewportSize = scrollState.viewportSize,
+                            fadeFraction = fadeFraction
+                        )
 
                         drawRect(
                             brush = brush,
@@ -223,21 +229,26 @@ internal fun computeDomainEndScrollValue(
 }
 
 @VisibleForTesting
-internal fun createDomainHighlightBrush(
-    text: String,
-    highlightRange: Pair<Int, Int>?,
+internal fun createUrlFadeBrush(
     scrolledPixels: Int,
+    maxScrollPixels: Int,
+    viewportSize: Int,
     fadeFraction: Float,
 ): Brush {
-    val brush = when {
-        // Don't fade the start if the text is not scrolled to fit the highlighted domain.
-         scrolledPixels == 0 -> Brush.horizontalGradient(
+    val fadeWidthPixels = viewportSize * fadeFraction
+    val needsLeftFade = scrolledPixels > 0
+    val remainingScroll = maxScrollPixels - scrolledPixels
+    val needsRightFade = remainingScroll > fadeWidthPixels
+
+    return when {
+        !needsLeftFade && !needsRightFade -> SolidColor(Color.Black)
+
+        !needsLeftFade && needsRightFade -> Brush.horizontalGradient(
             (1f - fadeFraction) to Color.Black,
             1f to Color.Transparent,
         )
 
-        // Don't fade the end if the highlight is also at the end of the text.
-        (highlightRange?.second ?: Int.MIN_VALUE) >= text.lastIndex -> Brush.horizontalGradient(
+        needsLeftFade && !needsRightFade -> Brush.horizontalGradient(
             0f to Color.Transparent,
             fadeFraction to Color.Black,
         )
@@ -251,7 +262,6 @@ internal fun createDomainHighlightBrush(
             ),
         )
     }
-    return brush
 }
 
 @Composable
diff --git a/mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrlTest.kt b/mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrlTest.kt
index 2919b133319..e48b327aaa3 100644
--- a/mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrlTest.kt
+++ b/mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrlTest.kt
@@ -9,6 +9,7 @@ import androidx.compose.ui.geometry.Rect
 import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.SolidColor
 import androidx.compose.ui.text.TextLayoutResult
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import mozilla.components.support.test.mock
@@ -91,43 +92,55 @@ class HighlightedDomainUrlTest {
     }
 
     @Test
-    fun `GIVEN the start of the URL should be highlighted THEN get an appropriate highlight brush`() {
-        val url = "pagedomain.com/testing"
-        scrollState.stubScrollInfo(url)
-        val highlightRange = computeHighlightRange(url, "pagedomain.com")
-        val scrolledPixels = computeDomainEndScrollValue(url, highlightRange)
+    fun `GIVEN the displayed URL does not overflow the available space WHEN creating the fading brush THEN set no fading`() {
+        val expected = SolidColor(Color.Black)
+
+        val result = createUrlFadeBrush(
+            scrolledPixels = 0,
+            maxScrollPixels = 0,
+            viewportSize = viewPortWidth.toInt(),
+            fadeFraction = 0.5f,
+        )
+
+        assertEquals(expected, result)
+    }
+
+    @Test
+    fun `GIVEN the displayed URL only overflows to the right WHEN creating the fading brush THEN fade the right edge`() {
         val expected = Brush.horizontalGradient(
             0.5f to Color.Black,
             1f to Color.Transparent,
         )
 
-        val result = createDomainHighlightBrush(url, highlightRange, scrolledPixels, 0.5f)
+        val result = createUrlFadeBrush(
+            scrolledPixels = 0,
+            maxScrollPixels = 600,
+            viewportSize = viewPortWidth.toInt(),
+            fadeFraction = 0.5f,
+        )
 
         assertEquals(expected, result)
     }
 
     @Test
-    fun `GIVEN the end of the URL should be highlighted THEN get an appropriate highlight brush`() {
-        val url = "subdomain.pagedomain.com"
-        scrollState.stubScrollInfo(url)
-        val highlightRange = computeHighlightRange(url, "pagedomain.com")
-        val scrolledPixels = computeDomainEndScrollValue(url, highlightRange)
+    fun `GIVEN the displayed URL only overflows to the left WHEN creating the fading brush THEN fade the left edge`() {
         val expected = Brush.horizontalGradient(
             0f to Color.Transparent,
             0.5f to Color.Black,
         )
 
-        val result = createDomainHighlightBrush(url, highlightRange, scrolledPixels, 0.5f)
+        val result = createUrlFadeBrush(
+            scrolledPixels = 600,
+            maxScrollPixels = 600,
+            viewportSize = viewPortWidth.toInt(),
+            fadeFraction = 0.5f,
+        )
 
         assertEquals(expected, result)
     }
 
     @Test
-    fun `GIVEN the middle of the URL should be highlighted THEN get an appropriate highlight brush`() {
-        val url = "subdomain.pagedomain.com/testing"
-        scrollState.stubScrollInfo(url)
-        val highlightRange = computeHighlightRange(url, "pagedomain.com")
-        val scrolledPixels = computeDomainEndScrollValue(url, highlightRange)
+    fun `GIVEN the displayed URL overflows on both sides WHEN creating the fading brush THEN fade both edges`() {
         val expected = Brush.horizontalGradient(
             colorStops = arrayOf(
                 0f to Color.Transparent,
@@ -137,7 +150,12 @@ class HighlightedDomainUrlTest {
             ),
         )
 
-        val result = createDomainHighlightBrush(url, highlightRange, scrolledPixels, 0.5f)
+        val result = createUrlFadeBrush(
+            scrolledPixels = 100,
+            maxScrollPixels = 1200,
+            viewportSize = viewPortWidth.toInt(),
+            fadeFraction = 0.5f,
+        )
 
         assertEquals(expected, result)
     }
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrlTest.kt b/mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrlTest.kt
index 2919b133319..e48b327aaa3 100644
--- a/mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrlTest.kt
+++ b/mobile/android/android-components/components/compose/browser-toolbar/src/test/java/mozilla/components/compose/browser/toolbar/ui/HighlightedDomainUrlTest.kt
@@ -9,6 +9,7 @@ import androidx.compose.ui.geometry.Rect
 import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.SolidColor
 import androidx.compose.ui.text.TextLayoutResult
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import mozilla.components.support.test.mock
@@ -91,43 +92,55 @@ class HighlightedDomainUrlTest {
     }
 
     @Test
-    fun `GIVEN the start of the URL should be highlighted THEN get an appropriate highlight brush`() {
-        val url = "pagedomain.com/testing"
-        scrollState.stubScrollInfo(url)
-        val highlightRange = computeHighlightRange(url, "pagedomain.com")
-        val scrolledPixels = computeDomainEndScrollValue(url, highlightRange)
+    fun `GIVEN the displayed URL does not overflow the available space WHEN creating the fading brush THEN set no fading`() {
+        val expected = SolidColor(Color.Black)
+
+        val result = createUrlFadeBrush(
+            scrolledPixels = 0,
+            maxScrollPixels = 0,
+            viewportSize = viewPortWidth.toInt(),
+            fadeFraction = 0.5f,
+        )
+
+        assertEquals(expected, result)
+    }
+
+    @Test
+    fun `GIVEN the displayed URL only overflows to the right WHEN creating the fading brush THEN fade the right edge`() {
         val expected = Brush.horizontalGradient(
             0.5f to Color.Black,
             1f to Color.Transparent,
         )
 
-        val result = createDomainHighlightBrush(url, highlightRange, scrolledPixels, 0.5f)
+        val result = createUrlFadeBrush(
+            scrolledPixels = 0,
+            maxScrollPixels = 600,
+            viewportSize = viewPortWidth.toInt(),
+            fadeFraction = 0.5f,
+        )
 
         assertEquals(expected, result)
     }
 
     @Test
-    fun `GIVEN the end of the URL should be highlighted THEN get an appropriate highlight brush`() {
-        val url = "subdomain.pagedomain.com"
-        scrollState.stubScrollInfo(url)
-        val highlightRange = computeHighlightRange(url, "pagedomain.com")
-        val scrolledPixels = computeDomainEndScrollValue(url, highlightRange)
+    fun `GIVEN the displayed URL only overflows to the left WHEN creating the fading brush THEN fade the left edge`() {
         val expected = Brush.horizontalGradient(
             0f to Color.Transparent,
             0.5f to Color.Black,
         )
 
-        val result = createDomainHighlightBrush(url, highlightRange, scrolledPixels, 0.5f)
+        val result = createUrlFadeBrush(
+            scrolledPixels = 600,
+            maxScrollPixels = 600,
+            viewportSize = viewPortWidth.toInt(),
+            fadeFraction = 0.5f,
+        )
 
         assertEquals(expected, result)
     }
 
     @Test
-    fun `GIVEN the middle of the URL should be highlighted THEN get an appropriate highlight brush`() {
-        val url = "subdomain.pagedomain.com/testing"
-        scrollState.stubScrollInfo(url)
-        val highlightRange = computeHighlightRange(url, "pagedomain.com")
-        val scrolledPixels = computeDomainEndScrollValue(url, highlightRange)
+    fun `GIVEN the displayed URL overflows on both sides WHEN creating the fading brush THEN fade both edges`() {
         val expected = Brush.horizontalGradient(
             colorStops = arrayOf(
                 0f to Color.Transparent,
@@ -137,7 +150,12 @@ class HighlightedDomainUrlTest {
             ),
         )
 
-        val result = createDomainHighlightBrush(url, highlightRange, scrolledPixels, 0.5f)
+        val result = createUrlFadeBrush(
+            scrolledPixels = 100,
+            maxScrollPixels = 1200,
+            viewportSize = viewPortWidth.toInt(),
+            fadeFraction = 0.5f,
+        )
 
         assertEquals(expected, result)
     }
Loading diff…