Medium firefox Sandbox Escape 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionLinks in a sandboxed iframe could open an external app on Android without the required "allow-" permission.
ComponentNetworking
Bug ClassSandbox Escape
Tracker1818679
Fix commit822ad7739fe2 (firefox) +14/-3
CISA KEVNot listed
CreditedAxel Chong (@Haxatron)
Disclosed2025-10-14

Changed Functions

FunctionChangeNotes
if
netwerk/ipc/DocumentLoadListener.cpp
modified

Files Changed

  • netwerk/ipc/DocumentLoadListener.cpp
  • uriloader/exthandler/nsExternalHelperAppService.cpp
  • uriloader/exthandler/nsExternalHelperAppService.h
diff --git a/netwerk/ipc/DocumentLoadListener.cpp b/netwerk/ipc/DocumentLoadListener.cpp
index b5392e08a2f..6cfb50d14c3 100644
--- a/netwerk/ipc/DocumentLoadListener.cpp
+++ b/netwerk/ipc/DocumentLoadListener.cpp
@@ -938,7 +938,9 @@ auto DocumentLoadListener::Open(nsDocShellLoadState* aLoadState,
   if (documentContext && aLoadState->LoadType() != LOAD_ERROR_PAGE &&
       !(aLoadState->HasInternalLoadFlags(
           nsDocShell::INTERNAL_LOAD_FLAGS_BYPASS_LOAD_URI_DELEGATE)) &&
-      !(aLoadState->LoadType() & LOAD_HISTORY)) {
+      !(aLoadState->LoadType() & LOAD_HISTORY) &&
+      !nsExternalHelperAppService::ExternalProtocolIsBlockedBySandbox(
+          documentContext, aLoadState->HasValidUserGestureActivation())) {
     nsCOMPtr<nsIWidget> widget =
         documentContext->GetParentProcessWidgetContaining();
     RefPtr<nsWindow> window = nsWindow::From(widget);
@@ -3132,7 +3134,8 @@ DocumentLoadListener::AsyncOnChannelRedirect(
       bc ? bc->GetParentProcessWidgetContaining() : nullptr;
   RefPtr<nsWindow> window = nsWindow::From(widget);
 
-  if (window) {
+  if (window && !nsExternalHelperAppService::ExternalProtocolIsBlockedBySandbox(
+                    bc, false)) {
     promise = window->OnLoadRequest(uriBeingLoaded,
                                     nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
                                     nsIWebNavigation::LOAD_FLAGS_IS_REDIRECT,
diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp
index f7b7b0710e2..4e04da8704a 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.cpp
+++ b/uriloader/exthandler/nsExternalHelperAppService.cpp
@@ -967,7 +967,7 @@ nsresult nsExternalHelperAppService::EscapeURI(nsIURI* aURI, nsIURI** aResult) {
   return ios->NewURI(escapedSpec, nullptr, nullptr, aResult);
 }
 
-bool ExternalProtocolIsBlockedBySandbox(
+bool nsExternalHelperAppService::ExternalProtocolIsBlockedBySandbox(
     BrowsingContext* aBrowsingContext,
     const bool aHasValidUserGestureActivation) {
   if (!StaticPrefs::dom_block_external_protocol_navigation_from_sandbox()) {
diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h
index 26dfc6f0429..78c8199490b 100644
--- a/uriloader/exthandler/nsExternalHelperAppService.h
+++ b/uriloader/exthandler/nsExternalHelperAppService.h
@@ -129,6 +129,14 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService,
   // Internal method. Only called directly from tests.
   static nsresult EscapeURI(nsIURI* aURI, nsIURI** aResult);
 
+  /**
+   * Check whether `aBrowsingContext` is sandboxed such that external
+   * protocol navigations performed in that context would be blocked.
+   */
+  static bool ExternalProtocolIsBlockedBySandbox(
+      mozilla::dom::BrowsingContext* aBrowsingContext,
+      const bool aHasValidUserGestureActivation);
+
   /**
    * Logging Module. Usage: set MOZ_LOG=HelperAppService:level, where level
    * should be 2 for errors, 3 for debug messages from the cross- platform
Loading diff…