Firefox · Core
CVE-2026-2800
Logic Error in Core
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
AlwaysDeniedSchemesmobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AlwaysDeniedSchemes.kt |
modified | |
AppLinksInterceptormobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksInterceptor.kt |
modified | |
AppLinksUseCasesmobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksUseCases.kt |
modified |
Files Changed
mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AlwaysDeniedSchemes.ktmobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksInterceptor.ktmobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksUseCases.ktmobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksInterceptorTest.ktmobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksUseCasesTest.kt
Patch
diff --git a/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AlwaysDeniedSchemes.kt b/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AlwaysDeniedSchemes.kt
new file mode 100644
index 00000000000..9584e720897
--- /dev/null
+++ b/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AlwaysDeniedSchemes.kt
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package mozilla.components.feature.app.links
+
+import java.util.Locale
+
+/**
+ * Utility class whether scheme is allowed or denied.
+ */
+class AlwaysDeniedSchemes(private val schemes: Set<String>) {
+ /**
+ * Whether or not we should deny given URI scheme by dangerous etc.
+ *
+ * @param scheme A scheme of URI
+ * @return `true` If scheme should be denied
+ */
+ fun shouldDeny(scheme: String?): Boolean {
+ return schemes.contains(scheme?.lowercase(Locale.ROOT))
+ }
+}
diff --git a/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksInterceptor.kt b/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksInterceptor.kt
index 96512c2e113..35160e4d497 100644
--- a/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksInterceptor.kt
+++ b/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksInterceptor.kt
@@ -60,7 +60,7 @@ private val ALLOWED_SCHEMES_IN_SUBFRAME: List<String> = listOf(
class AppLinksInterceptor(
private val context: Context,
private val engineSupportedSchemes: Set<String> = ENGINE_SUPPORTED_SCHEMES,
- private val alwaysDeniedSchemes: Set<String> = ALWAYS_DENY_SCHEMES,
+ private val alwaysDeniedSchemes: AlwaysDeniedSchemes = AlwaysDeniedSchemes(ALWAYS_DENY_SCHEMES),
private var launchInApp: () -> Boolean = { false },
private val useCases: AppLinksUseCases = AppLinksUseCases(
context,
@@ -102,7 +102,7 @@ class AppLinksInterceptor(
// If scheme not in supported list then follow user preference
!launchInApp() && !isPossibleAuthentication(tabSessionState) && engineSupportsScheme -> true
// Never go to an external app when scheme is in blocklist
- alwaysDeniedSchemes.contains(uriScheme) -> true
+ alwaysDeniedSchemes.shouldDeny(uriScheme) -> true
else -> false
}
diff --git a/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksUseCases.kt b/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksUseCases.kt
index 8b136f3f1ed..b851ed978f2 100644
--- a/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksUseCases.kt
+++ b/mobile/android/android-components/components/feature/app-links/src/main/java/mozilla/components/feature/app/links/AppLinksUseCases.kt
@@ -52,7 +52,7 @@ private const val ANDROID_RESOLVER_PACKAGE_NAME = "android"
class AppLinksUseCases(
private val context: Context,
private var launchInApp: () -> Boolean = { false },
- private val alwaysDeniedSchemes: Set<String> = ALWAYS_DENY_SCHEMES,
+ private val alwaysDeniedSchemes: AlwaysDeniedSchemes = AlwaysDeniedSchemes(ALWAYS_DENY_SCHEMES),
private val installedBrowsers: Browsers = BrowsersCache.all(context),
) {
@Suppress(
@@ -159,7 +159,7 @@ class AppLinksUseCases(
val appIntent = when {
intent?.data == null -> null
- alwaysDeniedSchemes.contains(intent.data?.scheme) -> null
+ alwaysDeniedSchemes.shouldDeny(intent.data?.scheme) -> null
else -> intent
}
@@ -249,7 +249,7 @@ class AppLinksUseCases(
appIntent?.let {
try {
val scheme = appIntent.data?.scheme
- if (scheme != null && alwaysDeniedSchemes.contains(scheme)) {
+ if (alwaysDeniedSchemes.shouldDeny(scheme)) {
return
}
diff --git a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksInterceptorTest.kt b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksInterceptorTest.kt
index eb0b5cfb7b3..d3e1aa66794 100644
--- a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksInterceptorTest.kt
+++ b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksInterceptorTest.kt
@@ -202,7 +202,7 @@ class AppLinksInterceptorTest {
val blocklistedScheme = "blocklisted"
val feature = AppLinksInterceptor(
context = mockContext,
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { true },
useCases = mockUseCases,
)
@@ -259,7 +259,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { false },
useCases = mockUseCases,
)
@@ -279,7 +279,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(notSupportedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(notSupportedScheme)),
launchInApp = { false },
useCases = mockUseCases,
)
@@ -300,7 +300,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { true },
useCases = mockUseCases,
)
@@ -321,7 +321,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { false },
useCases = mockUseCases,
)
@@ -343,7 +343,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { false },
useCases = mockUseCases,
)
@@ -594,7 +594,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { true },
useCases = mockUseCases,
)
@@ -616,7 +616,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { false },
useCases = mockUseCases,
)
diff --git a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksUseCasesTest.kt b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksUseCasesTest.kt
index 9614cf363e0..a4de61e4d4a 100644
--- a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksUseCasesTest.kt
+++ b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksUseCasesTest.kt
@@ -357,7 +357,7 @@ class AppLinksUseCasesTest {
fun `A intent scheme denied should return no app intent`() {
val uri = "intent://details/#Intent"
val context = createContext(Triple(uri, appPackage, ""))
- val subject = AppLinksUseCases(context, { true }, alwaysDeniedSchemes = setOf("intent"))
+ val subject = AppLinksUseCases(context, { true }, alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf("intent")))
val redirect = subject.interceptedAppLinkRedirect.invoke(uri)
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/AppLinksInterceptorTest.kt b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksInterceptorTest.kt
index eb0b5cfb7b3..d3e1aa66794 100644
--- a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksInterceptorTest.kt
+++ b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksInterceptorTest.kt
@@ -202,7 +202,7 @@ class AppLinksInterceptorTest {
val blocklistedScheme = "blocklisted"
val feature = AppLinksInterceptor(
context = mockContext,
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { true },
useCases = mockUseCases,
)
@@ -259,7 +259,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { false },
useCases = mockUseCases,
)
@@ -279,7 +279,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(notSupportedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(notSupportedScheme)),
launchInApp = { false },
useCases = mockUseCases,
)
@@ -300,7 +300,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { true },
useCases = mockUseCases,
)
@@ -321,7 +321,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { false },
useCases = mockUseCases,
)
@@ -343,7 +343,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { false },
useCases = mockUseCases,
)
@@ -594,7 +594,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { true },
useCases = mockUseCases,
)
@@ -616,7 +616,7 @@ class AppLinksInterceptorTest {
val feature = AppLinksInterceptor(
context = mockContext,
engineSupportedSchemes = setOf(supportedScheme),
- alwaysDeniedSchemes = setOf(blocklistedScheme),
+ alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf(blocklistedScheme)),
launchInApp = { false },
useCases = mockUseCases,
)
diff --git a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksUseCasesTest.kt b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksUseCasesTest.kt
index 9614cf363e0..a4de61e4d4a 100644
--- a/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksUseCasesTest.kt
+++ b/mobile/android/android-components/components/feature/app-links/src/test/java/mozilla/components/feature/app/links/AppLinksUseCasesTest.kt
@@ -357,7 +357,7 @@ class AppLinksUseCasesTest {
fun `A intent scheme denied should return no app intent`() {
val uri = "intent://details/#Intent"
val context = createContext(Triple(uri, appPackage, ""))
- val subject = AppLinksUseCases(context, { true }, alwaysDeniedSchemes = setOf("intent"))
+ val subject = AppLinksUseCases(context, { true }, alwaysDeniedSchemes = AlwaysDeniedSchemes(setOf("intent")))
val redirect = subject.interceptedAppLinkRedirect.invoke(uri)
Loading diff…
References
On This Page