Closed Bug 1966927 (CVE-2025-6427) Opened 10 months ago Closed 10 months ago

closed windows and removed iframes can be used to bypass an inherited connect-src CSP and hide network activity from the DevTools

Categories

(Core :: DOM: Security, defect, P2)

defect

Tracking

()

VERIFIED FIXED
141 Branch
Tracking Status
firefox-esr115 --- wontfix
firefox-esr128 --- wontfix
firefox139 --- wontfix
firefox140 + verified
firefox141 + verified

People

(Reporter: lebr0nli, Assigned: tschuster, NeedInfo)

References

Details

(Keywords: csectype-priv-escalation, reporter-external, sec-moderate, Whiteboard: [client-bounty-form][adv-main140+])

Attachments

(4 files, 2 obsolete files)

Attached file poc.html

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:138.0) Gecko/20100101 Firefox/138.0

Summary:

By using fetch, navigator.sendBeacon, EventSource, and WebSocket from the detached window of a removed iframe, the attacker can bypass the connect-src CSP, also the network activity initiated by these functions will not be shown in the Network tab of the DevTools.

Steps to reproduce:

  1. Host the attached poc.html file on a server at http://<hostname>/poc.html.
  2. Even though the connect-src directive is set to none at http://<hostname>/poc.html, after visiting, you should notice 4 request being sent to <hostname> (POST /fetch, POST /sendBeacon, GET /EventSource, and GET /WebSocket). In addition, if you open DevTools and reload the page, you should notice these 4 requests to <hostname> do not appear in the Network tab. This behavior can be used to hide certain attack traffic while the victim is debugging with DevTools.

Actual results:

connect-src is bypassed and the network activity is hidden from the DevTools.

Expected results:

connect-src should not be bypassed and the network activity should be visible in the DevTools.

Flags: sec-bounty?
Group: firefox-core-security → network-core-security
Component: Security → DOM: Networking
Product: Firefox → Core

This one is pretty bizarre. The added frame is an empty about:blank document, and those inherit the CSP of the context that created it in order to prevent this from being an easy way to bypass CSP. And while the frame is attached to the document the CSP inheritance is working great -- all the requests are blocked, and the network attempts show up in dev tools. Once you detach it, though, we forget the CSP and the requests go through. As reported, they no longer show up on the Web Console, but you can see them in the multiprocess mode of the Browser Console.

I thought maybe the completely empty frame in the POC didn't initialize something and become its own document, but if I alter the testcase to document.write() some content into the frame the behavior is the same: connections blocked while the frame is attached, and if I've kept a reference you can still send Beacons etc that are now NOT blocked by the CSP

I tried with an iframe.srcdoc and had the same bug with an intriguing minor difference. In the about:blank case I used a relative path in the sendBeacon() call and even when detached it was resolved relative to the baseURI as I'd expect. A relative URL also worked in the about:srcdoc case when the iframe was attached, but once removed from the document I had to specify an absolute URI to make the beacon go through.

Then I tried window.open(). It inherited the CSP and blocked the beacon as it should (the blocked request shows up in the Web Console of the popup, not the original page). I then closed the popup and tried sending the beacon again using the saved reference and it was not blocked by CSP

This very likely applies to other inherited security properties like iframe sandbox or referrer-policy. Maybe to permissions-policy permission grants or restrictions.

Status: UNCONFIRMED → NEW
Component: DOM: Networking → DOM: Security
Ever confirmed: true
Summary: Certain functions from a window of removed iframe can be used to bypass the connect-src CSP and hide network activity from the DevTools → closed windows and removed iframes can be used to bypass an inherited connect-src CSP and hide network activity from the DevTools
Group: network-core-security → dom-core-security

In CSPService::ConsultCSP we get the CSP via LoadInfo::GetCSP, which returns a nullptr and thus we don't do any CSP checks.

LoadInfo::GetCSP returns nullptr, because mClientInfo.isNothing() is true. This is true, because when creating the LoadInfo, aLoadingContext->OwnerDoc()->GetClientInfo() is Nothing.

Document::GetClientInfo returns Nothing, because both GetOriginalDocument() and GetInnerWindow() return a nullptr.

Assignee: nobody → tschuster
Depends on: 1967261
Depends on: 1967417
Severity: -- → S3
Priority: -- → P2
Depends on: 1967731

So, I think I have a general fix for this using the LoadInfo::Create function introduced in bug 1967417. We will simply not allow creating LoadInfos for documents with a missing ClientInfo. Currently there are still quite a few exceptions (like allowing everything in the parent process) because we aren't really ready to enforce this everywhere. This approach has the big advantage that it's going to be a lot harder to miss some types of loads (e.g. importScripts in Workers).

However I am not sure how uplift-able that approach is going to be. For uplifting we might want to go with a less invasive approach and instead add explicit checks to the APIs used by the testcase.

I don't think we need to worry about uplifting for a bug of moderate severity. It would look different if people were able to bypass stronger security guarantees than a connect-src CSP (like the Same-Origin Policy, the sandbox flag or a script-src directive).

Attachment #9490003 - Attachment description: WIP: Bug 1966927 - Check the ClientInfo when creating a LoadInfo → Bug 1966927 - Check the ClientInfo when creating a LoadInfo. r?smaug
Depends on: 1968179
Pushed by tschuster@mozilla.com: https://hg.mozilla.org/integration/autoland/rev/29e37de220e8 Check the ClientInfo when creating a LoadInfo. r=necko-reviewers,smaug
Group: dom-core-security → core-security-release
Status: NEW → RESOLVED
Closed: 10 months ago
Resolution: --- → FIXED
Target Milestone: --- → 141 Branch
Flags: sec-bounty? → sec-bounty+

Given the number of dependent bugs we'd have to backport with this, and the lowish severity impact, we can skip an ESR backport. The next ESR branch, Firefox ESR 140, arrives in a month anyway.

The patch landed in nightly and beta is affected.
:tschuster, is this bug important enough to require an uplift?

For more information, please visit BugBot documentation.

Flags: needinfo?(tschuster)

I actually think we should uplift this together with bug 1967731 to 140, especially because it's the next ESR. I believe all other preliminary patches are already in 140.

Next week is the final week of beta for Fx140.
Tom, are you planning to add a beta uplift request here along with Bug 1967731?

Comment on attachment 9490003 [details]
Bug 1966927 - Check the ClientInfo when creating a LoadInfo. r?smaug

Beta/Release Uplift Approval Request

  • User impact if declined/Reason for urgency: We don't properly protect pages that use Content-Security-Policies in certain situations (removed iframes).
    The test case however does not show code execution.
  • Is this code covered by automated tests?: No
  • Has the fix been verified in Nightly?: Yes
  • Needs manual test from QE?: No
  • If yes, steps to reproduce:
  • List of other uplifts needed: Bug 1967731
  • Risk to taking this patch: Medium
  • Why is the change risky/not risky? (and alternatives if risky): This is a pretty big change, but also quite targeted for this specific situation.
  • String changes made/needed:
  • Is Android affected?: Yes
Flags: needinfo?(tschuster)

Comment on attachment 9490003 [details]
Bug 1966927 - Check the ClientInfo when creating a LoadInfo. r?smaug

Adding uplift request flag to the attachment

Attachment #9490003 - Flags: approval-mozilla-beta?

Comment on attachment 9490003 [details]
Bug 1966927 - Check the ClientInfo when creating a LoadInfo. r?smaug

Approved for 140.0b7

Attachment #9490003 - Flags: approval-mozilla-beta? → approval-mozilla-beta+
QA Whiteboard: [sec] [uplift] [qa-triage-done-c141/b140] [qa-ver-needed-c141/b140]
Flags: qe-verify+

Reproduced the initial issue using Firefox 138.0, verified that using latest Nightly 141.0a1 and Firefox 140.0b7 across platforms (Windows 11, macOS 13 and Ubuntu 22.04) the issue is fixed now, no POST /fetch, POST /sendBeacon, GET /EventSource, and GET /WebSocket requests are recorded in the server and we have activity in the Network tab from DevTools.

Status: RESOLVED → VERIFIED
QA Whiteboard: [sec] [uplift] [qa-triage-done-c141/b140] [qa-ver-needed-c141/b140] → [sec] [uplift] [qa-triage-done-c141/b140] [qa-ver-done-c141/b140]
Flags: qe-verify+
Regressions: 1971809
Regressions: 1972225
No longer regressions: 1972225
Whiteboard: [client-bounty-form] → [client-bounty-form][adv-main140+]
Attached file advisory.txt (obsolete) —
Attached file advisory.txt (obsolete) —
Attachment #9495578 - Attachment is obsolete: true
Attached file advisory.txt
Attachment #9495644 - Attachment is obsolete: true
Alias: CVE-2025-6427
Flags: needinfo?(tschuster)
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: