Closed Bug 2049981 (CVE-2026-16399) Opened 4 months ago Closed 3 months ago

PBrowser::NewWindowGlobal accepts a WindowGlobalInit for a BrowsingContext not owned by the sender

Categories

(Core :: DOM: Navigation, defect)

defect

Tracking

()

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

People

(Reporter: iifizzyx, Assigned: nika)

References

(Blocks 1 open bug)

Details

(Keywords: csectype-site-isolation, reporter-external, sec-moderate, Whiteboard: [client-bounty-form][adv-main153+])

Attachments

(4 files, 2 external files)

Attached file poc.patch —

Tested build

  • Version: Firefox Nightly 154.0a1
  • BuildID: 20260624061603
  • Platform: Ubuntu 24.04.4 LTS, Linux 6.8.0-124-generic, x86_64
  • Build config: default source build, MOZCONFIG unset
  • Runtime config: fresh profile, no preference overrides, sandbox/e10s-disabling environment variables unset

Summary

A compromised content process can send PBrowser::NewWindowGlobal through one BrowserChild while placing another same-group BrowsingContext ID in WindowGlobalInit.context().mBrowsingContextId.

BrowserParent::RecvNewWindowGlobal verifies that the target context exists and that its BrowsingContextGroup is known to the child process, but it does not reject a target CanonicalBrowsingContext that is not owned by the sending ContentParent. WindowGlobalParent::CreateDisconnected then resolves the foreign target from the supplied ID, and WindowGlobalParent::Init() installs the attacker-owned actor as the target context's current window global.

The PoC validates this on default Nightly by making an attacker-owned WindowGlobalParent current for a victim top-level BrowsingContext:

The marker name fakeEndpoint means a separate forged PWindowGlobal endpoint created by the diagnostic to model a compromised content process constructing an extra actor with fresh window IDs. It does not mean the disclosed restore or login data is fake; those values come from normal sessionstore and password-manager storage prepared in the test profile.

[WGP-XBC child] source=17179869185 target=4 sourceInProcess=1 targetInProcess=0 targetingTop=1 fakeEndpoint=1 forgedDocURI=http://127.0.0.1:8000/top-target-source.html
[WGP-XBC fake-child] source=17179869185 target=4 realInner=17179869187 fakeInner=17179869188 fakeOuter=17179869189 targetingTop=1
[WGP-XBC parent-recv] receiverBC=6442450945 targetBC=4 ownedBySender=0 sameAsReceiver=0
[WGP-XBC active] targetBC=4 ownerProcess=3 targetContentProcess=3 actorContentProcess=8 isCurrent=1 isActiveInTab=1 actorBrowserIsReceiver=1 crossManager=1
[WGP-XBC parent-accepted] targetBC=4 inner=17179869188 ownedBySenderBeforeInit=0

Impact

This is not only state corruption. The corrupted currentWindowGlobal is consumed by real parent subsystems and routes restricted browser data to the unauthorized actor.

Validated impact 1: real saved sessionstore form data is sent to the attacker-owned child actor. The profile was generated with normal sessionstore-backups/recovery.jsonlz4 crash-restore state containing a saved victim-frame form field:

victim_secret = WGP-XBC-REAL-RESTORE-SECRET-20260624

The parent selected restore data for victim targetBC=12884901889, whose owner process was 8, and delivered/deserialized it through the forged actor in process 6:

[WGP-XBC fake-child] source=12884901890 target=12884901889 realInner=12884901893 fakeInner=12884901894 fakeOuter=12884901895 targetingTop=0
[WGP-XBC restore-early-parent] targetBC=12884901889 topBC=11 gotPath=1 pathLength=1 hasRestoreData=1 wgpDocURI=http://127.0.0.2:8000/target.html?static_target=1
[WGP-XBC restore-ipc-read-entry] isXPath=0 id=victim_secret value=WGP-XBC-REAL-RESTORE-SECRET-20260624
[WGP-XBC active] targetBC=12884901889 ownerProcess=8 targetContentProcess=8 actorContentProcess=6 isCurrent=1 isActiveInTab=1 actorBrowserIsReceiver=1 crossManager=1
[WGP-XBC restore-request-parent] bc=12884901889 ownerProcess=8 actorProcess=6 ancestorsCurrent=1 hasRestoreData=1
[WGP-XBC restore-child] childBC=12884901889 restoreUrl=http://127.0.0.2:8000/target.html?static_target=1

Validated impact 2: saved-login credentials for the victim/top origin are selected by the parent password manager and delivered to the attacker-owned child actor. The validation selects the login origin from windowGlobal.documentURI, proving the parent selected the victim/top document origin http://127.0.0.1:8000, not the source-frame origin:

[WGP-XBC login-probe-parent-prepared] origin=http://127.0.0.1:8000 username=wgp_xbc_login_user password=WGP-XBC-LOGIN-SECRET-20260624
[WGP-XBC child] source=17179869185 target=10 sourceInProcess=1 targetInProcess=0 targetingTop=1 fakeEndpoint=1 forgedDocURI=http://127.0.0.1:8000/top-target-source.html
[WGP-XBC fake-child] source=17179869185 target=10 realInner=17179869187 fakeInner=17179869188 fakeOuter=17179869189 targetingTop=1
[WGP-XBC active] targetBC=10 ownerProcess=5 targetContentProcess=5 actorContentProcess=8 isCurrent=1 isActiveInTab=1 actorBrowserIsReceiver=1 crossManager=1
[WGP-XBC login-probe-parent-send] targetBC=10 actorBC=10 origin=http://127.0.0.1:8000 username=wgp_xbc_login_user password=WGP-XBC-LOGIN-SECRET-20260624
[WGP-XBC login-probe-child] childBC=10 loginFormOrigin=http://127.0.0.1:8000 username=wgp_xbc_login_user password=WGP-XBC-LOGIN-SECRET-20260624

A fresh 10-run stress pass reproduced the corrected saved-login disclosure every time:

docuri_success_child_markers=10/10
wrong_origin_child_markers=0/10
abort_markers=0/10
crash_markers=0/10
profiles_with_minidumps=0/10

This demonstrates parent-to-less-privileged-process disclosure of saved browser data in the compromised-content-process threat model. I am not claiming parent/native code execution.

Attached files

  • report.md: issue summary, impact, reproduction, and fix guidance.
  • root_cause.md: root-cause analysis and invariant violation.
  • validation.log: tested build, commands, and fresh validation markers.
  • poc.patch: focused diagnostic patch for c1395f54bdda7cb0ed71bbe54e2940ce16175389.
  • run_wgp_xbc_poc.sh: self-contained runner that creates the temporary local site and restore profile, applies poc.patch if needed, builds, and runs the top-WGP, restore-data, and saved-login validations.

Reproduction

Run from the submission directory:

./run_wgp_xbc_poc.sh /path/to/firefox-source all

The source checkout should be at commit c1395f54bdda7cb0ed71bbe54e2940ce16175389.

The runner uses env -u to explicitly remove environment variables that would disable sandboxing/e10s; it does not disable those protections.

Flags: sec-bounty?
Attached file run_wgp_xbc_poc.sh —
Attached file validation.log —
Attached file root_cause.md —
Group: firefox-core-security → dom-core-security
Component: Security → DOM: Content Processes
Product: Firefox → Core
Component: DOM: Content Processes → DOM: Navigation

Nika, do you know why bug 2038695 isn't enough for this?

Flags: needinfo?(nika)

I thought I had already made this change, but apparently not. I've definitely written this code before, but it must not have landed.

This is just a small extra check to make sure that the BrowsingContext can be managed by the specific PBrowser actor.

I think this is the only call-site where a check like this needs to be added.

Flags: needinfo?(nika)
Attached file (secure) —
Assignee: nobody → nika
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Attachment #9604309 - Flags: approval-mozilla-beta?

firefox-beta Uplift Approval Request

  • User impact if declined/Reason for urgency: Sandboxing IPC boundary violation which could lead to strange behaviour.
  • Code covered by automated testing?: yes
  • Fix verified in Nightly?: yes
  • Needs manual QE testing?: no
  • Steps to reproduce for manual QE testing:
  • Risk associated with taking this patch: low
  • Explanation of risk level: Straightforward small fix.
  • String changes made/needed?: None
  • Is Android affected?: yes
Group: dom-core-security → core-security-release
Status: ASSIGNED → RESOLVED
Closed: 3 months ago
Resolution: --- → FIXED
Target Milestone: --- → 154 Branch
Attachment #9604309 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
QA Whiteboard: [sec] [qa-triage-done-c154/b153]
Whiteboard: [client-bounty-form] → [client-bounty-form][adv-main153+]
Alias: CVE-2026-16399
Flags: sec-bounty? → sec-bounty+
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: