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)
Tracking
()
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)
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:
- Host the attached
poc.htmlfile on a server athttp://<hostname>/poc.html. - Even though the
connect-srcdirective is set tononeathttp://<hostname>/poc.html, after visiting, you should notice 4 request being sent to<hostname>(POST /fetch,POST /sendBeacon,GET /EventSource, andGET /WebSocket). In addition, if you open DevTools and reload the page, you should notice these 4 requests to<hostname>do not appear in theNetworktab. 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.
Updated•10 months ago
|
Comment 1•10 months ago
|
||
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.
Updated•10 months ago
|
Updated•10 months ago
|
| Assignee | ||
Comment 2•10 months ago
|
||
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 | ||
Updated•10 months ago
|
Updated•10 months ago
|
| Assignee | ||
Comment 3•10 months ago
|
||
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.
Comment 4•10 months ago
|
||
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).
| Assignee | ||
Comment 5•10 months ago
|
||
Updated•10 months ago
|
| Assignee | ||
Comment 6•10 months ago
|
||
Comment 8•10 months ago
|
||
Updated•10 months ago
|
Comment 9•10 months ago
|
||
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.
Comment 10•10 months ago
|
||
The patch landed in nightly and beta is affected.
:tschuster, is this bug important enough to require an uplift?
- If yes, please nominate the patch for beta approval.
- See https://wiki.mozilla.org/Release_Management/Requesting_an_Uplift for documentation on how to request an uplift.
- If no, please set
status-firefox140towontfix.
For more information, please visit BugBot documentation.
Updated•10 months ago
|
| Assignee | ||
Comment 11•9 months ago
|
||
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.
Comment 12•9 months ago
|
||
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?
| Assignee | ||
Comment 13•9 months ago
|
||
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
Comment 14•9 months ago
|
||
Comment on attachment 9490003 [details]
Bug 1966927 - Check the ClientInfo when creating a LoadInfo. r?smaug
Adding uplift request flag to the attachment
Comment 15•9 months ago
|
||
Comment on attachment 9490003 [details]
Bug 1966927 - Check the ClientInfo when creating a LoadInfo. r?smaug
Approved for 140.0b7
Comment 16•9 months ago
|
||
| uplift | ||
Updated•9 months ago
|
Updated•9 months ago
|
Comment 17•9 months ago
|
||
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.
Updated•9 months ago
|
Comment 18•9 months ago
|
||
Comment 19•9 months ago
|
||
Comment 20•9 months ago
|
||
Updated•9 months ago
|
| Assignee | ||
Updated•4 months ago
|
Updated•3 months ago
|
Description
•