Open Bug 1467998 Opened 6 years ago Updated 6 months ago

<script> element without "cross-origin" attribute treats service worker synthesized CORS response as opaque

Categories

(Core :: DOM: Service Workers, defect, P3)

Unspecified
All
defect

Tracking

()

REOPENED
Tracking Status
firefox60 --- affected
firefox61 --- affected
firefox62 --- affected

People

(Reporter: prakashsharma97, Unassigned)

References

(Blocks 1 open bug)

Details

(Whiteboard: dom-lws-bugdash-triage)

User Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36 Steps to reproduce: Visit https://raw.cm2.pw/Firefox/ Actual results: The script error, "ReferenceError: foo is not defined", is written in <textarea>. Though the `script` src is is of same-origin, the request is intercepted and changed by Service Worker which first fetches the content from https://api.ipify.org/?callback=foo&format=jsonp and appends `/* ALTERED */`. The content, however, is made readable with CORS policy. If the content is not readable or requested with 'no-cors', a generic "script error" is thrown. Thus, the behavior cannot be considered a security/privacy issue. Expected results: Errors should only be available to same-origin requests.
I managed to reproduce the issue on Firefox 60.0.2, Firefox 61.0b7, and Nightly 62.0a1 (2018-06-12), on Windows 10, Ubuntu 16.04 and Mac OS. Marking it as new on DOM:Service Workers component.
Status: UNCONFIRMED → NEW
Component: Untriaged → DOM: Service Workers
Ever confirmed: true
OS: Unspecified → All
Product: Firefox → Core
Version: 60 Branch → Trunk
FYI, it works in all modern browsers (Safari, not testd). I'm not sure if it's intentional or if I should report it to all vendors.
The service worker script is not actually passing a cors response to respondWith(). Its doing this: self.addEventListener('fetch', event => { let [,url] = event.request.url.match(/fake\.php\?url=(.+)/) || []; if(url){ console.info('Bypassing SOP for: ' + url); event.respondWith(modify(unescape(url))); } }); const modify = url => { return fetch(url, {mode: 'cors', redirect: 'follow'}).then(response=>response.text()).then(text=>{ if(text) console.log(text); return new Response(text + '/* ALTERED */'); }); } In particular note that its doing: return new Response(text + '/* ALTERED */'); This is synthesizing a new Response without any associated URL. The browser has no practical way to tell if the body that was based to such a Response constructor originated from a CORS cross-origin source. So this behavior is expected and by design. An origin is allowed to lie to itself via its own same-origin service worker. And we allow the service worker to read cross-origin CORS-protected data. One question, though, if you change your test to return the CORS response from the fetch() directly without altering it, what happens? I expect you should get muted script errors in firefox in that case.
The whole idea behind <script crossorigin> is that you get non-muted errors for cross-origin scripts. This is all by design.
Status: NEW → RESOLVED
Closed: 6 years ago
Resolution: --- → INVALID
Well, the <script> element in this case does not have the cross-origin attribute.
Ah right, in that case per the standard it should not be muted. If we do, we might want to fix that. I'll reopen.
Status: RESOLVED → REOPENED
Resolution: INVALID → ---
Priority: -- → P2
(In reply to Ben Kelly [:bkelly] from comment #3) > One question, though, if you change your test to return the CORS response > from the fetch() directly without altering it, what happens? I expect you > should get muted script errors in firefox in that case. Yeah, if I return cors response from fetch() directly, I get generic "script errors" message.
Ok. Anne, do you think that is a bug then? I guess the error muting CORs type check should use the actual response type?
Flags: needinfo?(annevk)
Yeah, at least as far as I can remember we didn't change the standard on the response being authoritative (even though most implementations work differently for the moment). (We did add a restriction that a "same-origin" fetch cannot take a "cors" response as that would result in rather tricky downstream scenarios.)
Flags: needinfo?(annevk)
Ok, then this is very similar to bug 1467454. I'll morph this bug into a similar issue for script muting. The fix should be to adjust this code: https://searchfox.org/mozilla-central/rev/d544b118e26422877108c42723b26e9bb4539721/dom/script/ScriptLoader.cpp#2101 To look at the LoadInfo tainting value instead of doing a cross-origin principal subsumes check. Or maybe it could do both if we want a system principal to still be able to get full script errors even for an opaque tainted result.
Summary: Service Worker - Script error leakage if CORS enabled → <script> element without "cross-origin" attribute treats service worker synthesized CORS response as opaque
Severity: normal → S3
Priority: P2 → P3
Whiteboard: dom-lws-bugdash-triage
You need to log in before you can comment on or make changes to this bug.