Medium firefox Sandbox Escape 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactmoderate
DescriptionSandbox escape in the DOM: Networking component
ComponentDOM
Bug ClassSandbox Escape
Tracker2043845
Fix commitf8b0b712028c (firefox) +46/-3
CISA KEVNot listed
CreditedYaqoub Aldurayhim
Disclosed2026-07-21

Files Changed

  • dom/base/Document.cpp
  • dom/base/Document.h
  • dom/fetch/FetchParent.cpp
  • dom/security/nsContentSecurityManager.cpp
  • modules/libpref/init/StaticPrefList.yaml
  • netwerk/base/nsNetUtil.cpp
diff --git a/dom/base/Document.cpp b/dom/base/Document.cpp
index 85d3493fff4..9c7acbe17a0 100644
--- a/dom/base/Document.cpp
+++ b/dom/base/Document.cpp
@@ -1616,6 +1616,13 @@ void Document::ReloadWithHttpsOnlyException() {
   }
 }
 
+void Document::ForceSkipDTDSecurityChecks() {
+  MOZ_ASSERT(StaticPrefs::dom_fetch_allow_force_allowed_dtd(),
+             "Loading DTDs that skip security checks requires "
+             "dom.fetch.allow_force_allowed_dtd to be enabled");
+  mSkipDTDSecurityChecks = true;
+}
+
 // Given an nsresult that is assumed to be synthesized by PSM and describes a
 // certificate or TLS error, attempts to convert it into a string
 // representation of the underlying NSS error.
diff --git a/dom/base/Document.h b/dom/base/Document.h
index 42c105bb323..63c60ffe411 100644
--- a/dom/base/Document.h
+++ b/dom/base/Document.h
@@ -3066,7 +3066,7 @@ class Document : public nsINode,
 
   void ForceEnableXULXBL() { mAllowXULXBL = eTriTrue; }
 
-  void ForceSkipDTDSecurityChecks() { mSkipDTDSecurityChecks = true; }
+  void ForceSkipDTDSecurityChecks();
 
   /**
    * Returns the template content owner document that owns the content of
diff --git a/dom/fetch/FetchParent.cpp b/dom/fetch/FetchParent.cpp
index 512b1305ef4..8c046ee2964 100644
--- a/dom/fetch/FetchParent.cpp
+++ b/dom/fetch/FetchParent.cpp
@@ -15,6 +15,7 @@
 #include "mozilla/dom/ProcessIsolation.h"
 #include "mozilla/dom/ServiceWorkerDescriptor.h"
 #include "mozilla/ipc/BackgroundParent.h"
+#include "nsIContentPolicy.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla::ipc;
@@ -123,6 +124,14 @@ IPCResult FetchParent::RecvFetchOp(FetchOpArgs&& aArgs) {
     }
   }
 
+  if (contentHandle &&
+      aArgs.request().contentPolicyType() ==
+          nsIContentPolicy::TYPE_INTERNAL_FORCE_ALLOWED_DTD &&
+      !StaticPrefs::dom_fetch_allow_force_allowed_dtd()) {
+    return IPC_FAIL(this,
+                    "RecvFetchOp FORCE_ALLOWED_DTD not allowed from content");
+  }
+
   mRequest = MakeSafeRefPtr<InternalRequest>(std::move(aArgs.request()));
   mIsWorkerFetch = aArgs.isWorkerRequest();
   mPrincipalInfo = std::move(aArgs.principalInfo());
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index 4278fcf8761..d7af515730f 100644
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -281,7 +281,8 @@ static nsresult DoCheckLoadURIChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) {
   // In practice, these DTDs are just used for localization, so applying the
   // same principal check as Fluent.
   if (aLoadInfo->InternalContentPolicyType() ==
-      nsIContentPolicy::TYPE_INTERNAL_DTD) {
+          nsIContentPolicy::TYPE_INTERNAL_DTD &&
+      mozilla::StaticPrefs::dom_fetch_allow_force_allowed_dtd()) {
     RefPtr<Document> doc;
     aLoadInfo->GetLoadingDocument(getter_AddRefs(doc));
     bool allowed = false;
@@ -295,7 +296,8 @@ static nsresult DoCheckLoadURIChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) {
   // that need to access localization DTDs. We just allow through
   // TYPE_INTERNAL_FORCE_ALLOWED_DTD no matter what the triggering principal is.
   if (aLoadInfo->InternalContentPolicyType() ==
-      nsIContentPolicy::TYPE_INTERNAL_FORCE_ALLOWED_DTD) {
+          nsIContentPolicy::TYPE_INTERNAL_FORCE_ALLOWED_DTD &&
+      mozilla::StaticPrefs::dom_fetch_allow_force_allowed_dtd()) {
     return NS_OK;
   }
 
diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml
index 7370b663313..e2fe1e8deb6 100644
--- a/modules/libpref/init/StaticPrefList.yaml
+++ b/modules/libpref/init/StaticPrefList.yaml
@@ -3147,6 +3147,18 @@
   value: true
   mirror: always
 
+# Whether to allow the TYPE_INTERNAL_FORCE_ALLOWED_DTD content policy type on
+# fetch requests received from a content process. Only consumers such as
+# Thunderbird that still rely on DTD loads should enable this.
+- name: dom.fetch.allow_force_allowed_dtd
+  type: RelaxedAtomicBool
+#if defined(MOZ_THUNDERBIRD)
+  value: true
+#else
+  value: false
+#endif
+  mirror: always
+
 - name: dom.fetchObserver.enabled
   type: RelaxedAtomicBool
   value: false
diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp
index 7636af5ef8a..9941a85331b 100644
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -17,6 +17,7 @@
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/StaticPrefs_browser.h"
+#include "mozilla/StaticPrefs_dom.h"
 #include "mozilla/StaticPrefs_extensions.h"
 #include "mozilla/StaticPrefs_network.h"
 #include "mozilla/StaticPrefs_privacy.h"
@@ -286,6 +287,13 @@ nsresult NS_NewChannelInternal(
   // loadinfo attached.
   NS_ENSURE_ARG_POINTER(outChannel);
 
+  if (aLoadInfo &&
+      aLoadInfo->InternalContentPolicyType() ==
+          nsIContentPolicy::TYPE_INTERNAL_FORCE_ALLOWED_DTD &&
+      !mozilla::StaticPrefs::dom_fetch_allow_force_allowed_dtd()) {
+    return NS_ERROR_CONTENT_BLOCKED;
+  }
+
   nsCOMPtr<nsIIOService> grip;
   nsresult rv = net_EnsureIOService(&aIoService, grip);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -452,6 +460,11 @@ nsresult NS_NewChannelInternal(
     uint32_t aSandboxFlags /* = 0 */) {
   NS_ENSURE_ARG_POINTER(outChannel);
 
+  if (aContentPolicyType == nsIContentPolicy::TYPE_INTERNAL_FORCE_ALLOWED_DTD &&
+      !mozilla::StaticPrefs::dom_fetch_allow_force_allowed_dtd()) {
+    return NS_ERROR_CONTENT_BLOCKED;
+  }
+
   nsCOMPtr<nsIIOService> grip;
   nsresult rv = net_EnsureIOService(&aIoService, grip);
   NS_ENSURE_SUCCESS(rv, rv);
Loading diff…