Low firefox Logic Error 🔧 Commit mapped

Overview

Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impactlow
DescriptionMitigation bypass in the DOM: Security component
ComponentDOM
Bug ClassLogic Error
Tracker2016915
Fix commitfa33a51e85e6 (firefox) +248/-169
CISA KEVNot listed
Creditedlebr0nli
Disclosed2026-04-21

Changed Functions

FunctionChangeNotes
CreateFromCSP
dom/security/OffThreadCSPContext.cpp
modified
WorkerCSPContext
dom/security/OffThreadCSPContext.h
modified
OffThreadCSPContext
dom/security/OffThreadCSPContext.h
modified
if
dom/workers/WorkerLoadInfo.cpp
modified
if
dom/worklet/WorkletImpl.cpp
modified

Files Changed

  • dom/security/OffThreadCSPContext.cpp
  • dom/security/OffThreadCSPContext.h
  • dom/security/moz.build
  • dom/security/trusted-types/TrustedTypePolicyFactory.cpp
  • dom/workers/RuntimeService.cpp
  • dom/workers/WorkerCSPContext.cpp
  • dom/workers/WorkerCSPContext.h
  • dom/workers/WorkerLoadInfo.cpp
  • dom/workers/WorkerLoadInfo.h
  • dom/workers/WorkerPrivate.cpp
  • dom/workers/WorkerPrivate.h
  • dom/workers/moz.build
  • dom/workers/remoteworkers/RemoteWorkerChild.cpp
  • dom/worklet/WorkletImpl.cpp
  • dom/worklet/WorkletImpl.h
  • dom/worklet/WorkletThread.cpp
diff --git a/dom/workers/WorkerCSPContext.cpp b/dom/security/OffThreadCSPContext.cpp
similarity index 79%
rename from dom/workers/WorkerCSPContext.cpp
rename to dom/security/OffThreadCSPContext.cpp
index cefbac2c1bc..a06a1a86e73 100644
--- a/dom/workers/WorkerCSPContext.cpp
+++ b/dom/security/OffThreadCSPContext.cpp
@@ -2,11 +2,10 @@
  * 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/. */
 
-#include "WorkerCSPContext.h"
+#include "OffThreadCSPContext.h"
 
+#include "MainThreadUtils.h"
 #include "mozilla/StaticPrefs_dom.h"
-#include "mozilla/dom/WorkerCommon.h"
-#include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/nsCSPParser.h"
 #include "mozilla/dom/nsCSPUtils.h"
 #include "mozilla/ipc/BackgroundUtils.h"
@@ -15,24 +14,24 @@
 namespace mozilla::dom {
 
 /* static */
-Result<UniquePtr<WorkerCSPContext>, nsresult> WorkerCSPContext::CreateFromCSP(
-    nsIContentSecurityPolicy* aCSP) {
-  AssertIsOnMainThread();
+Result<UniquePtr<OffThreadCSPContext>, nsresult>
+OffThreadCSPContext::CreateFromCSP(nsIContentSecurityPolicy* aCSP) {
+  MOZ_ASSERT(NS_IsMainThread());
 
   mozilla::ipc::CSPInfo cspInfo;
   nsresult rv = CSPToCSPInfo(aCSP, &cspInfo);
   if (NS_FAILED(rv)) {
     return Err(rv);
   }
-  return MakeUnique<WorkerCSPContext>(std::move(cspInfo));
+  return MakeUnique<OffThreadCSPContext>(std::move(cspInfo));
 }
 
-const nsTArray<UniquePtr<const nsCSPPolicy>>& WorkerCSPContext::Policies() {
+const nsTArray<UniquePtr<const nsCSPPolicy>>& OffThreadCSPContext::Policies() {
   EnsureIPCPoliciesRead();
   return mPolicies;
 }
 
-bool WorkerCSPContext::IsEvalAllowed(bool& aReportViolation) {
+bool OffThreadCSPContext::IsEvalAllowed(bool& aReportViolation) {
   MOZ_ASSERT(!aReportViolation);
 
   bool trustedTypesRequired =
@@ -54,7 +53,7 @@ bool WorkerCSPContext::IsEvalAllowed(bool& aReportViolation) {
   return true;
 }
 
-bool WorkerCSPContext::IsWasmEvalAllowed(bool& aReportViolation) {
+bool OffThreadCSPContext::IsWasmEvalAllowed(bool& aReportViolation) {
   MOZ_ASSERT(!aReportViolation);
   for (const UniquePtr<const nsCSPPolicy>& policy : Policies()) {
     // Either 'unsafe-eval' or 'wasm-unsafe-eval' can allow this
@@ -71,8 +70,8 @@ bool WorkerCSPContext::IsWasmEvalAllowed(bool& aReportViolation) {
   return true;
 }
 
-void WorkerCSPContext::EnsureIPCPoliciesRead() {
-  MOZ_DIAGNOSTIC_ASSERT(!!GetCurrentThreadWorkerPrivate());
+void OffThreadCSPContext::EnsureIPCPoliciesRead() {
+  MOZ_ASSERT(!NS_IsMainThread());
 
   if (!mPolicies.IsEmpty() || mCSPInfo.policyInfos().IsEmpty()) {
     return;
diff --git a/dom/workers/WorkerCSPContext.h b/dom/security/OffThreadCSPContext.h
similarity index 68%
rename from dom/workers/WorkerCSPContext.h
rename to dom/security/OffThreadCSPContext.h
index f33d497feee..5f73b14b23e 100644
--- a/dom/workers/WorkerCSPContext.h
+++ b/dom/security/OffThreadCSPContext.h
@@ -2,8 +2,8 @@
  * 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/. */
 
-#ifndef mozilla_dom_workers_WorkerCSPContext_h_
-#define mozilla_dom_workers_WorkerCSPContext_h_
+#ifndef mozilla_dom_OffThreadCSPContext_h_
+#define mozilla_dom_OffThreadCSPContext_h_
 
 #include "mozilla/Result.h"
 #include "mozilla/UniquePtr.h"
@@ -15,12 +15,13 @@ class nsIContentSecurityPolicy;
 
 namespace mozilla::dom {
 
-// A minimal version of nsCSPContext that can run on Worker threads.
-class WorkerCSPContext final {
+// A minimal version of nsCSPContext that can run on worker and worklet threads.
+class OffThreadCSPContext final {
  public:
-  explicit WorkerCSPContext(mozilla::ipc::CSPInfo&& aInfo) : mCSPInfo(aInfo) {}
+  explicit OffThreadCSPContext(mozilla::ipc::CSPInfo&& aInfo)
+      : mCSPInfo(aInfo) {}
 
-  static Result<UniquePtr<WorkerCSPContext>, nsresult> CreateFromCSP(
+  static Result<UniquePtr<OffThreadCSPContext>, nsresult> CreateFromCSP(
       nsIContentSecurityPolicy* aCSP);
 
   const mozilla::ipc::CSPInfo& CSPInfo() const { return mCSPInfo; }
@@ -35,15 +36,14 @@ class WorkerCSPContext final {
   // Thread boundaries require us to not only store a CSP object, but also a
   // serialized version of the CSP. Reason being: Serializing a CSP to a CSPInfo
   // needs to happen on the main thread, but storing the CSPInfo needs to happen
-  // on the worker thread. We move the CSPInfo into the Client within
-  // ScriptExecutorRunnable::PreRun().
+  // on the worker/worklet thread.
   mozilla::ipc::CSPInfo mCSPInfo;
 
-  // This is created lazily by parsing the policies in CSPInfo on the worker
-  // thread.
+  // This is created lazily by parsing the policies in CSPInfo on the
+  // worker/worklet thread.
   nsTArray<UniquePtr<const nsCSPPolicy>> mPolicies;
 };
 
 }  // namespace mozilla::dom
 
-#endif  // mozilla_dom_workers_WorkerCSPContext_h_
+#endif  // mozilla_dom_OffThreadCSPContext_h_
diff --git a/dom/security/moz.build b/dom/security/moz.build
index 147a4dacf3e..f865c75a2a9 100644
--- a/dom/security/moz.build
+++ b/dom/security/moz.build
@@ -29,6 +29,7 @@ EXPORTS.mozilla.dom += [
     "nsHTTPSOnlyStreamListener.h",
     "nsHTTPSOnlyUtils.h",
     "nsMixedContentBlocker.h",
+    "OffThreadCSPContext.h",
     "PolicyContainer.h",
     "PolicyTokenizer.h",
     "ReferrerInfo.h",
@@ -64,6 +65,7 @@ UNIFIED_SOURCES += [
     "nsHTTPSOnlyStreamListener.cpp",
     "nsHTTPSOnlyUtils.cpp",
     "nsMixedContentBlocker.cpp",
+    "OffThreadCSPContext.cpp",
     "PolicyContainer.cpp",
     "PolicyTokenizer.cpp",
     "ReferrerInfo.cpp",
diff --git a/dom/security/trusted-types/TrustedTypePolicyFactory.cpp b/dom/security/trusted-types/TrustedTypePolicyFactory.cpp
index 656a56126f2..ab5ed351972 100644
--- a/dom/security/trusted-types/TrustedTypePolicyFactory.cpp
+++ b/dom/security/trusted-types/TrustedTypePolicyFactory.cpp
@@ -157,7 +157,7 @@ auto TrustedTypePolicyFactory::ShouldTrustedTypePolicyCreationBeBlockedByCSP(
     if (NS_WARN_IF(rv.Failed())) {
       rv.SuppressException();
     }
-    if (WorkerCSPContext* ctx = workerPrivate->GetCSPContext()) {
+    if (OffThreadCSPContext* ctx = workerPrivate->GetCSPContext()) {
       for (const UniquePtr<const nsCSPPolicy>& policy : ctx->Policies()) {
         if (shouldBlock(policy.get())) {
           result = PolicyCreation::Blocked;
diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp
index 477490a0849..2d7ef850680 100644
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -555,12 +555,12 @@ MOZ_CAN_RUN_SCRIPT_FOR_DEFINITION bool ContentSecurityPolicyAllows(
       return true;
     }
 
-    if (WorkerCSPContext* ctx = worker->GetCSPContext()) {
+    if (OffThreadCSPContext* ctx = worker->GetCSPContext()) {
       evalOK = ctx->IsEvalAllowed(reportViolation);
     }
     violationType = nsIContentSecurityPolicy::VIOLATION_TYPE_EVAL;
   } else {
-    if (WorkerCSPContext* ctx = worker->GetCSPContext()) {
+    if (OffThreadCSPContext* ctx = worker->GetCSPContext()) {
       evalOK = ctx->IsWasmEvalAllowed(reportViolation);
     }
 
diff --git a/dom/workers/WorkerLoadInfo.cpp b/dom/workers/WorkerLoadInfo.cpp
index 9a10f3654e5..5d2542e984e 100644
--- a/dom/workers/WorkerLoadInfo.cpp
+++ b/dom/workers/WorkerLoadInfo.cpp
@@ -113,8 +113,8 @@ nsresult WorkerLoadInfo::SetPrincipalsAndCSPOnMainThread(
   mCSP = aCsp;
 
   if (mCSP) {
-    Result<UniquePtr<WorkerCSPContext>, nsresult> ctx =
-        WorkerCSPContext::CreateFromCSP(aCsp);
+    Result<UniquePtr<OffThreadCSPContext>, nsresult> ctx =
+        OffThreadCSPContext::CreateFromCSP(aCsp);
     if (NS_WARN_IF(ctx.isErr())) {
       return ctx.unwrapErr();
     }
diff --git a/dom/workers/WorkerLoadInfo.h b/dom/workers/WorkerLoadInfo.h
index a52a8cb1663..63b0645991d 100644
--- a/dom/workers/WorkerLoadInfo.h
+++ b/dom/workers/WorkerLoadInfo.h
@@ -12,8 +12,8 @@
 #include "mozilla/StorageAccess.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/dom/ChannelInfo.h"
+#include "mozilla/dom/OffThreadCSPContext.h"
 #include "mozilla/dom/ServiceWorkerRegistrationDescriptor.h"
-#include "mozilla/dom/WorkerCSPContext.h"
 #include "mozilla/dom/WorkerCommon.h"
 #include "mozilla/net/NeckoChannelParams.h"
 #include "nsIInterfaceRequestor.h"
@@ -70,7 +70,7 @@ struct WorkerLoadInfoData {
   nsCOMPtr<nsIScriptContext> mScriptContext;
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
   nsCOMPtr<nsIContentSecurityPolicy> mCSP;
-  UniquePtr<WorkerCSPContext> mCSPContext;
+  UniquePtr<OffThreadCSPContext> mCSPContext;
 
   nsCOMPtr<nsIChannel> mChannel;
   nsCOMPtr<nsILoadGroup> mLoadGroup;
diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp
index 5e961bdc5b0..115cbc60454 100644
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1409,7 +1409,7 @@ nsresult WorkerPrivate::SetCsp(nsIContentSecurityPolicy* aCSP) {
   aCSP->EnsureEventTarget(mMainThreadEventTarget);
 
   mLoadInfo.mCSP = aCSP;
-  auto ctx = WorkerCSPContext::CreateFromCSP(aCSP);
+  auto ctx = OffThreadCSPContext::CreateFromCSP(aCSP);
   if (NS_WARN_IF(ctx.isErr())) {
     return ctx.unwrapErr();
   }
@@ -1477,7 +1477,7 @@ nsresult WorkerPrivate::SetCSPFromHeaderValues(
 
   mLoadInfo.mCSP = csp;
 
-  auto ctx = WorkerCSPContext::CreateFromCSP(csp);
+  auto ctx = OffThreadCSPContext::CreateFromCSP(csp);
   if (NS_WARN_IF(ctx.isErr())) {
     return ctx.unwrapErr();
   }
diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h
index 62216aa3362..3110d859825 100644
--- a/dom/workers/WorkerPrivate.h
+++ b/dom/workers/WorkerPrivate.h
@@ -961,7 +961,7 @@ class WorkerPrivate final
     return mLoadInfo.mCSPContext->CSPInfo();
   }
 
-  WorkerCSPContext* GetCSPContext() const {
+  OffThreadCSPContext* GetCSPContext() const {
     return mLoadInfo.mCSPContext.get();
   }
 
diff --git a/dom/workers/moz.build b/dom/workers/moz.build
index 2f2948a7294..c7818826d18 100644
--- a/dom/workers/moz.build
+++ b/dom/workers/moz.build
@@ -17,7 +17,6 @@ EXPORTS.mozilla.dom += [
     "Worker.h",
     "WorkerChannelInfo.h",
     "WorkerCommon.h",
-    "WorkerCSPContext.h",
     "WorkerDebugger.h",
     "WorkerDebuggerManager.h",
     "WorkerDocumentListener.h",
@@ -61,7 +60,6 @@ UNIFIED_SOURCES += [
     "ScriptLoader.cpp",
     "Worker.cpp",
     "WorkerChannelInfo.cpp",
-    "WorkerCSPContext.cpp",
     "WorkerCSPEventListener.cpp",
     "WorkerDebugger.cpp",
     "WorkerDebuggerManager.cpp",
diff --git a/dom/workers/remoteworkers/RemoteWorkerChild.cpp b/dom/workers/remoteworkers/RemoteWorkerChild.cpp
index 006b2ec52c6..992a0227616 100644
--- a/dom/workers/remoteworkers/RemoteWorkerChild.cpp
+++ b/dom/workers/remoteworkers/RemoteWorkerChild.cpp
@@ -21,6 +21,7 @@
 #include "mozilla/dom/FetchEventOpProxyChild.h"
 #include "mozilla/dom/IndexedDatabaseManager.h"
 #include "mozilla/dom/MessagePort.h"
+#include "mozilla/dom/OffThreadCSPContext.h"
 #include "mozilla/dom/PolicyContainer.h"
 #include "mozilla/dom/RemoteWorkerTypes.h"
 #include "mozilla/dom/ServiceWorkerDescriptor.h"
@@ -30,7 +31,6 @@
 #include "mozilla/dom/ServiceWorkerShutdownState.h"
 #include "mozilla/dom/ServiceWorkerUtils.h"
 #include "mozilla/dom/SharedWorkerOp.h"
-#include "mozilla/dom/WorkerCSPContext.h"
 #include "mozilla/dom/WorkerError.h"
 #include "mozilla/dom/WorkerPrivate.h"
 #include "mozilla/dom/WorkerRef.h"
@@ -305,8 +305,8 @@ nsresult RemoteWorkerChild::ExecWorkerOnMainThread(
           clientInfo.ref().GetPolicyContainerArgs();
       if (policyContainerArgs.isSome() && policyContainerArgs->csp().isSome()) {
         info.mCSP = CSPInfoToCSP(*policyContainerArgs->csp(), nullptr);
-        mozilla::Result<UniquePtr<WorkerCSPContext>, nsresult> ctx =
-            WorkerCSPContext::CreateFromCSP(info.mCSP);
+        mozilla::Result<UniquePtr<OffThreadCSPContext>, nsresult> ctx =
+            OffThreadCSPContext::CreateFromCSP(info.mCSP);
         if (ctx.isErr()) {
           return ctx.unwrapErr();
         }
diff --git a/dom/worklet/WorkletImpl.cpp b/dom/worklet/WorkletImpl.cpp
index 47f030f3705..ebe030548a2 100644
--- a/dom/worklet/WorkletImpl.cpp
+++ b/dom/worklet/WorkletImpl.cpp
@@ -12,6 +12,7 @@
 #include "mozilla/NullPrincipal.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/Document.h"
+#include "mozilla/dom/PolicyContainer.h"
 #include "mozilla/dom/RegisterWorkletBindings.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/WorkletBinding.h"
@@ -60,11 +61,17 @@ WorkletImpl::WorkletImpl(nsPIDOMWindowInner* aWindow, nsIPrincipal* aPrincipal)
   mShouldResistFingerprinting = aWindow->AsGlobal()->ShouldResistFingerprinting(
       RFPTarget::IsAlwaysEnabledForPrecompute);
 
-  RefPtr<dom::Document> doc = nsGlobalWindowInner::Cast(aWindow)->GetDocument();
-  if (doc) {
+  if (RefPtr<dom::Document> doc =
+          nsGlobalWindowInner::Cast(aWindow)->GetDocument()) {
     mIsPrivateBrowsing = doc->IsInPrivateBrowsing();
     mOverriddenFingerprintingSettings =
         doc->GetOverriddenFingerprintingSettings();
+
+    if (auto* policy = PolicyContainer::Cast(doc->GetPolicyContainer())) {
+      ipc::PolicyContainerArgs policyContainer;
+      PolicyContainer::ToArgs(policy, policyContainer);
+      mPolicyContainer = Some(std::move(policyContainer));
+    }
   }
 }
 
@@ -114,6 +121,16 @@ dom::WorkletGlobalScope* WorkletImpl::GetGlobalScope() {
   return mGlobalScope;
 }
 
+dom::OffThreadCSPContext* WorkletImpl::GetCSPContext() {
+  dom::WorkletThread::AssertIsOnWorkletThread();
+
+  if (!mCSPContext && mPolicyContainer && mPolicyContainer->csp().isSome()) {
+    ipc::CSPInfo cspInfo(mPolicyContainer->csp().ref());
+    mCSPContext = MakeUnique<dom::OffThreadCSPContext>(std::move(cspInfo));
+  }
+  return mCSPContext.get();
+}
+
 void WorkletImpl::NotifyWorkletFinished() {
   MOZ_ASSERT(NS_IsMainThread());
 
@@ -127,6 +144,7 @@ void WorkletImpl::NotifyWorkletFinished() {
                              [self = RefPtr<WorkletImpl>(this)]() {
                                self->mFinishedOnExecutionThread = true;
                                self->mGlobalScope = nullptr;
+                               self->mCSPContext = nullptr;
                              }));
 
   mTerminated = true;
diff --git a/dom/worklet/WorkletImpl.h b/dom/worklet/WorkletImpl.h
index b73217ceb27..dcfc2cba3d8 100644
--- a/dom/worklet/WorkletImpl.h
+++ b/dom/worklet/WorkletImpl.h
@@ -12,6 +12,7 @@
 #include "mozilla/Maybe.h"
 #include "mozilla/OriginAttributes.h"
 #include "mozilla/OriginTrials.h"
+#include "mozilla/dom/OffThreadCSPContext.h"
 #include "mozilla/ipc/PBackgroundSharedTypes.h"
 #include "nsRFPService.h"
 
@@ -68,6 +69,7 @@ class WorkletImpl {
 
   // Execution thread only.
   dom::WorkletGlobalScope* GetGlobalScope();
+  dom::OffThreadCSPContext* GetCSPContext();
 
   // Any thread.
 
@@ -78,6 +80,9 @@ class WorkletImpl {
   }
   nsIPrincipal* Principal() const { return mPrincipal; }
   const ipc::PrincipalInfo& PrincipalInfo() const { return mPrincipalInfo; }
+  const Maybe<ipc::PolicyContainerArgs>& PolicyContainer() const {
+    return mPolicyContainer;
+  }
 
   const Maybe<nsID>& GetAgentClusterId() const { return mAgentClusterId; }
 
@@ -109,6 +114,7 @@ class WorkletImpl {
   // Modified only in constructor.
   ipc::PrincipalInfo mPrincipalInfo;
   nsCOMPtr<nsIPrincipal> mPrincipal;
+  Maybe<ipc::PolicyContainerArgs> mPolicyContainer;
 
   const WorkletLoadInfo mWorkletLoadInfo;
 
@@ -118,6 +124,7 @@ class WorkletImpl {
... (file diff truncated)
Loading diff…