Closed Bug 2022259 Opened 8 months ago Closed 4 months ago

SharedWorker: PBackground Sender Principal Completely Unverified (RecvPSharedWorkerConstructor)

Categories

(Core :: DOM: Service Workers, defect)

defect

Tracking

()

RESOLVED FIXED
153 Branch
Tracking Status
firefox-esr115 --- wontfix
firefox-esr140 --- wontfix
firefox152 --- wontfix
firefox153 + fixed
firefox154 + fixed

People

(Reporter: t.satoki111, Assigned: nika)

References

(Blocks 1 open bug)

Details

(4 keywords, Whiteboard: [client-bounty-form])

Attachments

(1 file, 1 obsolete file)

5.34 KB, application/x-javascript
Details
Attached file PoC.js —

Summary

RecvPSharedWorkerConstructor (BackgroundParentImpl.cpp) forwards child-supplied RemoteWorkerData with zero validation. The function body is cast + Initialize() + IPC_OK() — nothing else.

RemoteWorkerData contains principalInfo, loadingPrincipalInfo, resolvedScriptURL, etc. None are verified against the sending process's actual principal.

Downstream, RemoteWorkerManager::LaunchInternal uses the forged principal to call TransmitPermissionsAndCookiesAndBlobURLsForPrincipalInfo, injecting the victim origin's permissions, cookies, and BlobURL registrations into the target content process in one shot.

This is the only PBackground constructor with zero sender verification.

Attack Chain

Compromised content process (evil.com)
  │
  ▼ [1] PBackground IPC
  SendPSharedWorkerConstructor(RemoteWorkerData{
    principalInfo: victim.example.com,        // forged
    loadingPrincipalInfo: victim.example.com, // forged
    resolvedScriptURL: victim's worker script, // forged
  })
  │
  ▼ [2] BackgroundParentImpl.cpp RecvPSharedWorkerConstructor()
  actor->Initialize(aData, aWindowID, aPortIdentifier);
  return IPC_OK();
  // Validation: ZERO. Cast + Initialize + return only.
  │
  ▼ [3] SharedWorkerService.cpp GetOrCreateWorkerManagerOnMainThread()
  principal = PrincipalInfoToPrincipal(aData.principalInfo());
  // Pure deserialization. No sender binding.
  // remoteType is recomputed, but principal itself is used as-is.
  │
  ▼ [4] RemoteWorkerManager.cpp LaunchInternal()
  TransmitPermissionsAndCookiesAndBlobURLsForPrincipalInfo(
    contentParent, aData.principalInfo()  // forged principal
  );
  //   → TransmitPermissionsForPrincipal(victim)
  //   → TransmitBlobURLsForPrincipal(victim)
  //   → CookieServiceParent::UpdateCookieInContentList(victim)
  │
  ▼ Victim's permissions, cookies, BlobURLs injected into attacker process

Vulnerable Code

1. RecvPSharedWorkerConstructor — Zero Checks

ipc/glue/BackgroundParentImpl.cpp:

IPCResult BackgroundParentImpl::RecvPSharedWorkerConstructor(
    PSharedWorkerParent* aActor, const mozilla::dom::RemoteWorkerData& aData,
    const uint64_t& aWindowID,
    const mozilla::dom::MessagePortIdentifier& aPortIdentifier) {
  mozilla::dom::SharedWorkerParent* actor =
      static_cast<mozilla::dom::SharedWorkerParent*>(aActor);
  actor->Initialize(aData, aWindowID, aPortIdentifier);
  return IPC_OK();
}

2. LaunchInternal — Bulk Injection with Forged Principal

dom/workers/remoteworkers/RemoteWorkerManager.cpp:

void RemoteWorkerManager::LaunchInternal(..., const RemoteWorkerData& aData) {
  if (aTargetActor != mParentActor) {
    nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(__func__,
      [contentHandle = ..., principalInfo = aData.principalInfo()] {
        if (RefPtr<ContentParent> cp = contentHandle->GetContentParent()) {
          TransmitPermissionsAndCookiesAndBlobURLsForPrincipalInfo(
            cp, principalInfo);  // Forged principal used directly
        }
      });
    SchedulerGroup::Dispatch(r.forget());
  }
}

3. IPDL Protocol

dom/workers/sharedworkers/PSharedWorker.ipdl:

[ManualDealloc]
protocol PSharedWorker {
  manager PBackground;
  // No security annotations
};

Constructor arguments (RemoteWorkerData) defined in PBackground.ipdl. Child-to-parent direction.

Comparison with Other PBackground Constructors

IPC Handler Sender Check Impact Scope
RecvPSharedWorkerConstructor None (zero) permission + cookie + BlobURL + worker launch
RecvPLockManagerConstructor SystemPrincipal rejection only lock namespace
RecvCreateNotificationParent None notification permission

SharedWorker is the only zero-check constructor on PBackground.

Exploitation Scenarios

Scenario 1: Victim Credentials Theft

  1. Compromise a content process (JS engine exploit)
  2. Forge RemoteWorkerData with victim.example.com principal
  3. Parent calls TransmitPermissionsAndCookiesAndBlobURLsForPrincipalInfo, opening victim's cookie routing to the attacker process
  4. Access victim's cookies from the attacker process

Scenario 2: Attach to Existing SharedWorker

  1. Victim origin has a running SharedWorker
  2. Attacker forges constructor with matching principal + script URL
  3. SharedWorkerManager::MatchOnMainThread matches the existing manager
  4. MessagePort communication established with victim's SharedWorker

Scenario 3: BlobURL Hijacking

  1. Victim origin has registered BlobURLs
  2. Create SharedWorker with forged principal
  3. TransmitBlobURLsForPrincipal injects victim's BlobURL registrations into attacker process
  4. Access victim data via BlobURLs

Suggested Fix

// Add to RecvPSharedWorkerConstructor:
RefPtr<ContentParent> cp = BackgroundParent::GetContentParent(this);
if (cp) {
  auto claimed = PrincipalInfoToPrincipal(aData.principalInfo());
  if (claimed.isErr() || !cp->GetRemoteType().Equals(
      GetRemoteType(claimed.unwrap(), WorkerKind::WorkerKindShared))) {
    return IPC_FAIL(this, "SharedWorker principal mismatch");
  }
}

Structural fix: derive RemoteWorkerData principals on the parent side from the sender's verified identity.

Flags: sec-bounty?
Group: firefox-core-security → dom-core-security
Component: Security → DOM: Service Workers
Product: Firefox → Core
Status: UNCONFIRMED → NEW
Ever confirmed: true
Keywords: sec-want

The severity field is not set for this bug.
:mccr8, could you have a look please?

For more information, please visit BugBot documentation.

Flags: needinfo?(continuation)
Severity: -- → S3
Flags: needinfo?(continuation)
Duplicate of this bug: 2027994
Duplicate of this bug: 2032132
Duplicate of this bug: 2032298
Duplicate of this bug: 2032979
Duplicate of this bug: 2038594
Summary: SharedWorker: PBackground Sender Principal Completely Unverified → SharedWorker: PBackground Sender Principal Completely Unverified (RecvPSharedWorkerConstructor)
See Also: → CVE-2026-12294
See Also: → 2039990
No longer duplicate of this bug: 2027994
Duplicate of this bug: 2027994
Duplicate of this bug: 2027999
Duplicate of this bug: 2028006
No longer duplicate of this bug: 2028006

This is sketchy and fixing this would probably fix bug 2049149, too. Can you look at this? Thanks.

Flags: needinfo?(echuang)
Duplicate of this bug: 2050472
Depends on: 2039990
Flags: needinfo?(echuang)

Actually, I guess we are only verifying loadingPrincipalInfo and not principalInfo. principalInfo is the one that actually ends up being used for RemoteWorkerManager::GetRemoteType. https://searchfox.org/firefox-main/rev/d5171e9e0f4729494423b0524f289073e0f0cb6c/dom/workers/sharedworkers/SharedWorkerService.cpp#190,213,237-239

Verification for partitionedPrincipal is also missing.

Attached file (secure) (obsolete) —

Simply adding BackgroundParent::ValidatePrincipalInfo for principalInfo (as a did in the patch above) causes crashes such as in the WPT mixed-content/gen/iframe-inherit.meta/opt-in/sharedworker-classic.https.html. In that case the principal's originNoSuffix is http://web-platform.test:8000 while aRemoteType is webIsolated=https://web-platform.test.

I would have assumed that shared workers aren't shared across https and http, so this feels a bit surprising to me.

Ah actually we already check the principal and loadingPrincipal, but only later and we fail gracefully: https://phabricator.services.mozilla.com/D302414

I think we could call this fixed?

Flags: needinfo?(nika)
Attachment #9601849 - Attachment is obsolete: true

Yeah I think this should be fixed. That was at least partially the intention of that patch stack.

Status: NEW → RESOLVED
Closed: 4 months ago
Flags: needinfo?(nika)
Resolution: --- → FIXED
Assignee: nobody → nika
Group: dom-core-security → core-security-release
Target Milestone: --- → 153 Branch
QA Whiteboard: [sec] [uplift] [qa-triage-done-c154/b153]
Flags: sec-bounty? → sec-bounty-
Duplicate of this bug: 2063503
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: