Closed Bug 2077355 Opened 1 month ago Closed 15 days ago

Crash in nsDocShell::PerformTrustedTypesPreNavigationCheck on javascript: link click in about:blank tabs without policy container (follow-up to bug 2003517)

Categories

(Core :: DOM: Security, defect)

Firefox 159
defect

Tracking

()

RESOLVED FIXED
161 Branch
Tracking Status
firefox161 --- fixed

People

(Reporter: europolwantme, Assigned: freddy, NeedInfo)

References

Details

(Keywords: csectype-nullptr, reporter-external, Whiteboard: [nosec][deduped])

Attachments

(1 file, 2 external files)

Attached file evidence.zip —

Steps to reproduce

Environment: Firefox Nightly 159.0a1 (mozilla-central, linux-x86_64, build 2026-10-02, ftp.mozilla.org/pub/firefox/nightly/latest-mozilla-central). Deterministic: 18/18 crashing runs across multiple harness variants. Firefox ESR 140.15.0 is not affected (no Trusted Types code). Harness: selenium 4.31 + geckodriver 0.37.1 under WSL2/Kali, gdb for the crash stack.

Manual steps:

  1. Settings -> New Tab page: disable the New Tab page (pref browser.newtabpage.enabled=false), so new tabs open about:blank - a supported user setting.
  2. Open a new tab (Ctrl+T) - a blank page appears.
  3. Open the DevTools console on that tab and evaluate:
document.body.innerHTML = '<a id="l" href="javascript:void(0)">x</a>';
document.getElementById('l').click();
  1. The content process crashes.

Both trusted input (WebDriver ElementClick) and script-initiated element.click() reproduce it - the Trusted Types check runs in DoURILoad before any user-activation gating. The same crash occurs in automation-created blank tabs (Marionette/WebDriver/Playwright startup tabs); a standalone Selenium reproducer is attached.

Controls that do NOT crash on this build:

  • The bug 2003517 repro window.open('javascript:...') - opens a blank tab, no crash (the RecvConstructBrowser fix works for that path).
  • about:blank created by typing in the URL bar - script executes normally (document gets a policy container).
  • http:, data:, blob: documents and about:blank popups/iframes inheriting a web origin - script executes normally.
  • https: link clicks in the affected documents - navigate normally (the check only runs for the javascript: scheme).
  • target=_blank activation of a javascript: link - opens a blank tab, no crash.
  • Firefox ESR 140.15.0 - script executes normally.

Actual results

The content process dies with SIGSEGV (deterministic). Parent-process log (independent runs):

A content process crashed and MOZ_CRASHREPORTER_SHUTDOWN is set, shutting down
[Parent 25316, IPC I/O Parent] WARNING: process 25455 exited on signal 11: file checkouts/gecko/ipc/chromium/src/chrome/common/process_watcher_posix_sigchld.cc:161
[Parent 29339, IPC I/O Parent] WARNING: process 29475 exited on signal 11: ... (clean env)
[Parent 35258, IPC I/O Parent] WARNING: process 35401 exited on signal 11: ... (NTP-disabled new tab)

Crash stack (gdb attached to the live content process):

#0  nsDocShell::PerformTrustedTypesPreNavigationCheck(nsDocShellLoadState*, nsGlobalWindowInner*) const+95
#1  nsDocShell::InternalLoad(nsDocShellLoadState*, mozilla::Maybe<unsigned int>)+...
#2  nsDocShell::OnLinkClickSync(nsIContent*, nsDocShellLoadState*, bool, nsIPrincipal*)+...
#3  OnLinkClickEvent::Run()+...
#4  mozilla::TaskController::ExecuteNextTaskOnlyMainThreadInternal(...)

Faulting sequence in the function (x/10i $rip-24): call *0x8(%rax) with rax=0 (virtual call through a null-derived object).

Root cause - docshell/base/nsDocShell.cpp (current mozilla-central), still unguarded:

nsresult nsDocShell::PerformTrustedTypesPreNavigationCheck(
    nsDocShellLoadState* aLoadState, nsGlobalWindowInner* aWindow) const {
  MOZ_ASSERT(aWindow);
  RefPtr<nsIContentSecurityPolicy> csp = aWindow->GetCsp();
  if (csp->GetRequireTrustedTypesForDirectiveState() ==   // <-- csp can be nullptr
      RequireTrustedTypesForDirectiveState::NONE) {
    return NS_OK;
  }

nsGlobalWindowInner::GetCsp() returns nullptr when the document has no CSP and no CSP snapshot exists (dom/base/nsGlobalWindowInner.cpp: if (mDoc) return mDoc->GetCsp(); ... return nullptr;). The caller (DoURILoad) invokes the check for every javascript:-scheme navigation when dom.security.trusted_types.enabled is on (default), without validating the CSP. A document without a CSP cannot have a require-trusted-types-for directive.

Relation to earlier bugs: bug 2003517 (same crash signature, repro window.open('javascript:...')) was fixed via bug 2002654 (Initialize policy container in RecvConstructBrowser, rev 72d46d7cb80e). That fix covers initial about:blank documents created via RecvConstructBrowser only. The documents in this report are created by navigating to about:blank (new-tab / openTrustedLinkIn flows with a system triggering principal, and automation startup tabs); those loads evidently still produce documents with no policy container, and the crashing function still has no defensive null check. The original 2003517 repro no longer crashes on this build - verified.

Impact: deterministic content-process crash (virtual call through a null pointer) in a navigation security check, reachable with one link click in the affected document class; no privileges required, activation not required beyond the click. The affected documents come from a supported user configuration (new tabs with the NTP disabled) and mainstream automation stacks (Marionette/WebDriver/Playwright) - the same impact class that made bug 2003517 actionable. The vulnerable code is enabled by default (Trusted Types) and would ride to release.

Expected results

No crash. The javascript: URL should be evaluated or ignored exactly like it is on http:/data:/blob: documents, on URL-bar-created about:blank tabs, and on Firefox ESR 140.15.0.

Suggested fix

  1. Harden the function (the generic fix originally attempted in bug 2002654 but scoped down to RecvConstructBrowser):
  RefPtr<nsIContentSecurityPolicy> csp = aWindow->GetCsp();
  if (!csp ||
      csp->GetRequireTrustedTypesForDirectiveState() ==
          RequireTrustedTypesForDirectiveState::NONE) {
    return NS_OK;
  }

(plus a release-build guard for aWindow; MOZ_ASSERT is debug-only)

  1. Audit the remaining about:blank creation paths (gBrowser.addTab / openTrustedLinkIn / automation startup tabs) for missing policy containers.

Attachments on this bug: attach-poc-manual.txt (manual repro), attach-poc-automated.py (standalone Selenium reproducer), attach-crash-stack.txt (symbolized gdb stack + disassembly), attach-crash-log.txt (SIGSEGV log excerpts), attach-differential.txt (control matrix incl. the fixed 2003517 repro).

Automatic triage (under development): sec-rating
No validation or verification has been performed.

Security rating: nosec

nsDocShell::PerformTrustedTypesPreNavigationCheck reads the CSP from the source window's policy container. When that container is missing, the CSP pointer is null, and the code calls a method on it without checking. The result is a guaranteed null-pointer dereference, which is a safe crash with no attacker-controlled offset. It only crashes the content process. Reaching it requires a document with no policy container, such as a new-tab about:blank, plus script run through DevTools or automation; web-origin documents are not affected. A safe content-process crash is not a security issue. It should still be fixed with a null check.

Group: firefox-core-security → dom-core-security
Component: Untriaged → DOM: Security
Product: Firefox → Core
Whiteboard: [nosec]
Whiteboard: [nosec] → [nosec][deduped]

This is just a null deref.

Group: dom-core-security

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

For more information, please visit BugBot documentation.

Flags: needinfo?(fbraun)
Assignee: nobody → fbraun
Attachment #9671235 - Attachment description: WIP: Bug 2077355 - Null-check the CSP in PerformTrustedTypesPreNavigationCheck. r?tschuster → Bug 2077355 - Null-check the CSP in PerformTrustedTypesPreNavigationCheck. r?tschuster
Status: UNCONFIRMED → ASSIGNED
Ever confirmed: true
Attachment #9671234 - Attachment description: WIP: Bug 2077355 - Always give about:blank documents a policy container. r?vhilla → Bug 2077355 - Always give about:blank documents a policy container. r?vhilla
Blocks: 2004943
Status: ASSIGNED → RESOLVED
Closed: 15 days ago
Resolution: --- → FIXED
Target Milestone: --- → 161 Branch
Duplicate of this bug: 2004943
QA Whiteboard: [qa-triage-done-c162/b161]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: