Medium firefox Logic Error 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionMalicious websites may have been able to perform user intent confirmation through tapjacking. This could have led to users unknowingly approving the launch of external applications, potentially exposing them to underlying vulnerabilities.
ComponentCore
Bug ClassLogic Error
Tracker1836921
Fix commita7a0cfe58556 (firefox) +26/-5
CISA KEVNot listed
CreditedShaheen Fazim
Disclosed2024-11-26

Changed Functions

FunctionChangeNotes
SimpleRedirectDialogFragment
mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragment.kt
modified

Files Changed

  • mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragment.kt
  • mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragmentTest.kt
diff --git a/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragment.kt b/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragment.kt
index 793c8c2ef68..5e56d06bca6 100644
--- a/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragment.kt
+++ b/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragment.kt
@@ -11,6 +11,7 @@ import androidx.annotation.StringRes
 import androidx.annotation.StyleRes
 import androidx.annotation.VisibleForTesting
 import androidx.appcompat.app.AlertDialog
+import mozilla.components.support.ktx.util.PromptAbuserDetector
 import mozilla.components.ui.widgets.withCenterAlignedButtons
 
 /**
@@ -23,6 +24,10 @@ import mozilla.components.ui.widgets.withCenterAlignedButtons
  */
 class SimpleRedirectDialogFragment : RedirectDialogFragment() {
 
+    @VisibleForTesting
+    internal var promptAbuserDetector =
+        PromptAbuserDetector(maxSuccessiveDialogSecondsLimit = TIME_SHOWN_OFFSET_SECONDS)
+
     @VisibleForTesting
     internal var testingContext: Context? = null
 
@@ -32,6 +37,8 @@ class SimpleRedirectDialogFragment : RedirectDialogFragment() {
             return if (themeID == 0) AlertDialog.Builder(context) else AlertDialog.Builder(context, themeID)
         }
 
+        promptAbuserDetector.updateJSDialogAbusedState()
+
         return with(requireBundle()) {
             val dialogTitleText = getInt(KEY_TITLE_TEXT, R.string.mozac_feature_applinks_normal_confirm_dialog_title)
             val dialogMessageString = getString(KEY_MESSAGE_STRING, "")
@@ -40,18 +47,29 @@ class SimpleRedirectDialogFragment : RedirectDialogFragment() {
             val themeResId = getInt(KEY_THEME_ID, 0)
             val cancelable = getBoolean(KEY_CANCELABLE, false)
 
-            getBuilder(themeResId)
+            val dialog = getBuilder(themeResId)
                 .setTitle(dialogTitleText)
                 .setMessage(dialogMessageString)
-                .setPositiveButton(positiveButtonText) { _, _ ->
-                    onConfirmRedirect()
-                }
+                .setPositiveButton(positiveButtonText) { _, _ -> }
                 .setNegativeButton(negativeButtonText) { _, _ ->
                     onCancelRedirect()
                 }
                 .setCancelable(cancelable)
                 .create()
-                .withCenterAlignedButtons()
+
+            dialog.withCenterAlignedButtons()
+            dialog.setOnShowListener {
+                val okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE)
+                okButton.setOnClickListener {
+                    if (promptAbuserDetector.areDialogsBeingAbused()) {
+                        promptAbuserDetector.updateJSDialogAbusedState()
+                    } else {
+                        onConfirmRedirect()
+                        dialog.dismiss()
+                    }
+                }
+            }
+            dialog
         }
     }
 
@@ -101,6 +119,7 @@ class SimpleRedirectDialogFragment : RedirectDialogFragment() {
         const val KEY_THEME_ID = "KEY_THEME_ID"
 
         const val KEY_CANCELABLE = "KEY_CANCELABLE"
+        private const val TIME_SHOWN_OFFSET_SECONDS = 1
     }
 
     private fun requireBundle(): Bundle {
diff --git a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragmentTest.kt b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragmentTest.kt
index 268e4df4d99..49ad38c71e5 100644
--- a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragmentTest.kt
+++ b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragmentTest.kt
@@ -13,6 +13,7 @@ import mozilla.components.support.test.mock
 import mozilla.components.support.test.robolectric.testContext
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.doNothing
@@ -27,6 +28,7 @@ class SimpleRedirectDialogFragmentTest {
     private val themeResId = appcompatR.style.Theme_AppCompat_Light
 
     @Test
+    @Ignore
     fun `Dialog confirmed callback is called correctly`() {
         var onConfirmCalled = false
         var onCancelCalled = false
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragmentTest.kt b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragmentTest.kt
index 268e4df4d99..49ad38c71e5 100644
--- a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragmentTest.kt
+++ b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/SimpleRedirectDialogFragmentTest.kt
@@ -13,6 +13,7 @@ import mozilla.components.support.test.mock
 import mozilla.components.support.test.robolectric.testContext
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
+import org.junit.Ignore
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.doNothing
@@ -27,6 +28,7 @@ class SimpleRedirectDialogFragmentTest {
     private val themeResId = appcompatR.style.Theme_AppCompat_Light
 
     @Test
+    @Ignore
     fun `Dialog confirmed callback is called correctly`() {
         var onConfirmCalled = false
         var onCancelCalled = false
Loading diff…