CSP: Allow Web Workers initiated from an isolated world to bypass the main world Content Security Policy
https://bugs.webkit.org/show_bug.cgi?id=153622
<rdar://problem/24400023>

Source/WebCore:

Reviewed by Gavin Barraclough.

Fixes an issue where Web Workers initiated from an isolated world (say, a Safari Content Script Extension)
would be subject to the Content Security Policy of the page.

Currently code in an isolated world that does not execute in a Web Worker is exempt from the CSP of
the page. However, code that runs inside a Web Worker that was initiated from an isolated world is
subject to the CSP of the page. Instead, such Web Worker code should also be exempt from the CSP of
the page.

Tests: http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval.html
       http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr.html
       http/tests/security/isolatedWorld/bypass-main-world-csp-worker.html

* Modules/websockets/WebSocket.cpp:
(WebCore::WebSocket::connect): Modified to ask the script execution context whether to bypass the
main world Content Security Policy now that script execution context knows this information.
* bindings/js/ScriptController.cpp:
(WebCore::ScriptController::shouldBypassMainWorldContentSecurityPolicy): Deleted; moved logic from here...
* bindings/js/ScriptController.h:
* dom/Document.cpp:
(WebCore::Document::shouldBypassMainWorldContentSecurityPolicy): ...to here.
* dom/Document.h:
* dom/ScriptExecutionContext.h:
(WebCore::ScriptExecutionContext::shouldBypassMainWorldContentSecurityPolicy): Added; defaults to false -
do not bypass the main world Content Security Policy.
* page/EventSource.cpp:
(WebCore::EventSource::create): Modified to ask the script execution context whether to bypass the
main world Content Security Policy now that script execution context knows this information.
* page/csp/ContentSecurityPolicy.cpp:
(WebCore::ContentSecurityPolicy::shouldBypassMainWorldContentSecurityPolicy): Deleted.
* page/csp/ContentSecurityPolicy.h:
* workers/AbstractWorker.cpp:
(WebCore::AbstractWorker::resolveURL): Bypass the main world Content Security Policy if applicable.
Added FIXME comment to enforce the child-src directive of the document's CSP (as opposed to the script-src
directive) on the worker's script URL. Also, scriptExecutionContext()->contentSecurityPolicy() should
always be non-null just as we expect scriptExecutionContext()->securityOrigin() to be non-null. Assert
this invariant to catch cases where a ScriptExecutionContext is not properly initialized.
* workers/DedicatedWorkerGlobalScope.cpp:
(WebCore::DedicatedWorkerGlobalScope::create): Modified to take boolean argument shouldBypassMainWorldContentSecurityPolicy
as to whether to bypass the main world Content Security Policy and only apply the Content Security
Policy headers when shouldBypassMainWorldContentSecurityPolicy is false.
(WebCore::DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope): Pass through a boolean argument shouldBypassMainWorldContentSecurityPolicy
as to whether to bypass the main world Content Security Policy.
* workers/DedicatedWorkerGlobalScope.h:
* workers/DedicatedWorkerThread.cpp:
(WebCore::DedicatedWorkerThread::DedicatedWorkerThread): Ditto.
(WebCore::DedicatedWorkerThread::createWorkerGlobalScope): Ditto.
* workers/DedicatedWorkerThread.h:
* workers/Worker.cpp:
(WebCore::Worker::create): Store whether we should bypass the main world Content Security Policy so
that we can pass it to WorkerMessagingProxy::startWorkerGlobalScope() in Worker::notifyFinished().
We need to store this decision here as opposed to determining it at any later time (say, in Worker::notifyFinished())
because it is dependent on the current JavaScript program stack at the time this function is invoked.
(WebCore::Worker::notifyFinished): Pass whether to bypass the main world Content Security Policy.
* workers/Worker.h:
* workers/WorkerGlobalScope.cpp:
(WebCore::WorkerGlobalScope::WorkerGlobalScope): Modified to take a boolean as to whether to bypass the
main world Content Security Policy and store it in a member field. Also, always instantiate a Content
Security Policy object as our current code assumes that one is always created.
* workers/WorkerGlobalScope.h:
* workers/WorkerGlobalScopeProxy.h:
* workers/WorkerMessagingProxy.cpp:
(WebCore::WorkerMessagingProxy::startWorkerGlobalScope): Pass through a boolean argument shouldBypassMainWorldContentSecurityPolicy
as to whether to bypass the main world Content Security Policy.
* workers/WorkerMessagingProxy.h:
* workers/WorkerThread.cpp:
(WebCore::WorkerThreadStartupData::WorkerThreadStartupData): Modified to take a boolean argument as to
whether to bypass the main world Content Security Policy and store it in a member field.
(WebCore::WorkerThread::WorkerThread): Pass through a boolean argument shouldBypassMainWorldContentSecurityPolicy
as to whether to bypass the main world Content Security Policy.
(WebCore::WorkerThread::workerThread): Ditto.
* workers/WorkerThread.h:
* xml/XMLHttpRequest.cpp:
(WebCore::XMLHttpRequest::open): Modified to ask the script execution context whether to bypass the
main world Content Security Policy now that script execution context knows this information.

LayoutTests:

Reviewed by Gavin Barraclough and Andy Estes.

Add tests to ensure that a Web Worker initiated from an isolated world can bypass the main world
Content Security Policy.

* http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval-expected.txt: Added.
* http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval.html: Added.
* http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr-expected.txt: Added.
* http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr.html: Added.
* http/tests/security/isolatedWorld/bypass-main-world-csp-worker-expected.txt: Added.
* http/tests/security/isolatedWorld/bypass-main-world-csp-worker.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@196242 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 64a3ea7..6b6d9a8 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,3 +1,21 @@
+2016-02-07  Daniel Bates  <dabates@apple.com>
+
+        CSP: Allow Web Workers initiated from an isolated world to bypass the main world Content Security Policy
+        https://bugs.webkit.org/show_bug.cgi?id=153622
+        <rdar://problem/24400023>
+
+        Reviewed by Gavin Barraclough and Andy Estes.
+
+        Add tests to ensure that a Web Worker initiated from an isolated world can bypass the main world
+        Content Security Policy.
+
+        * http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval-expected.txt: Added.
+        * http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval.html: Added.
+        * http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr-expected.txt: Added.
+        * http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr.html: Added.
+        * http/tests/security/isolatedWorld/bypass-main-world-csp-worker-expected.txt: Added.
+        * http/tests/security/isolatedWorld/bypass-main-world-csp-worker.html: Added.
+
 2016-02-07  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         REGRESSION(r195661): [GTK] Scrollbar tests crashing after overlay scrollbar groundwork
diff --git a/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval-expected.txt b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval-expected.txt
new file mode 100644
index 0000000..798ed76
--- /dev/null
+++ b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval-expected.txt
@@ -0,0 +1,3 @@
+This tests that in an isolated world the Content Security Policy of the parent origin (this page) is bypassed and a Web Worker is allowed to call eval().
+
+PASS worker called eval().
diff --git a/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval.html b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval.html
new file mode 100644
index 0000000..e61be4f
--- /dev/null
+++ b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'">
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+</script>
+</head>
+<body>
+<p>This tests that in an isolated world the Content Security Policy of the parent origin (this page) is bypassed and a Web Worker is allowed to call <code>eval()</code>.</p>
+<pre id="result"></pre>
+<script>
+window.onmessage = function (event)
+{
+    document.getElementById("result").textContent = event.data;
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function runTest()
+{
+    var script = [
+        'try {',
+        '    eval("1 + 0");',
+        '    self.postMessage("PASS worker called eval().");',
+        '} catch (exception) {',
+        '    self.postMessage("FAIL should not have thrown an exception. Threw exception " + exception + ".");',
+        '}',
+    ].join("\n");
+
+    var worker;
+    try {
+        worker = new Worker(window.URL.createObjectURL(new Blob([script])));
+        worker.onmessage = function (event) { window.postMessage(event.data, "*") };
+    } catch (exception) {
+        window.postMessage("FAIL should not have thrown an exception when creating worker. Threw exception " + exception + ".", "*");
+    }
+}
+
+if (window.testRunner)
+    testRunner.evaluateScriptInIsolatedWorld(0, runTest.toString() + ";runTest();");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr-expected.txt b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr-expected.txt
new file mode 100644
index 0000000..25fb110
--- /dev/null
+++ b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr-expected.txt
@@ -0,0 +1,3 @@
+This tests that in an isolated world the Content Security Policy of the parent origin (this page) is bypassed and a Web Worker is allowed to make an XHR request.
+
+PASS
diff --git a/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr.html b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr.html
new file mode 100644
index 0000000..8a24de7
--- /dev/null
+++ b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline'; connect-src 'none'">
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+</script>
+</head>
+<body>
+<p>This tests that in an isolated world the Content Security Policy of the parent origin (this page) is bypassed and a Web Worker is allowed to make an XHR request.</p>
+<pre id="result"></pre>
+<script>
+window.onmessage = function (event)
+{
+    document.getElementById("result").textContent = event.data;
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function runTest()
+{
+    var script = [
+        'var exception;',
+        'var xhr;',
+        'try {',
+        '    var isAsynchronous = false;',
+        '    xhr = new XMLHttpRequest;',
+        '    xhr.open("GET", "http://127.0.0.1:8000/xmlhttprequest/resources/get.txt", isAsynchronous);',
+        '    xhr.send();',
+        '} catch (e) {',
+        '    exception = e;',
+        '}',
+        'if (exception)',
+        '    self.postMessage("FAIL should not have thrown an exception. Threw exception " + exception + ".");',
+        'else',
+        '    self.postMessage(xhr.response);',
+    ].join("\n");
+
+    var worker;
+    try {
+        worker = new Worker(window.URL.createObjectURL(new Blob([script])));
+        worker.onmessage = function (event) { window.postMessage(event.data, "*") };
+    } catch (exception) {
+        window.postMessage("FAIL should not have thrown an exception when creating worker. Threw exception " + exception + ".", "*");
+    }
+}
+
+if (window.testRunner)
+    testRunner.evaluateScriptInIsolatedWorld(0, runTest.toString() + ";runTest();");
+</script>
+</body>
+</html>
diff --git a/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-expected.txt b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-expected.txt
new file mode 100644
index 0000000..d580a8c
--- /dev/null
+++ b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker-expected.txt
@@ -0,0 +1,3 @@
+This tests that in an isolated world the Content Security Policy of the parent origin (this page) is bypassed and a Web Worker is allowed to be instantiated with a script URL not listed in the CSP of the page.
+
+PASS worker instantiated.
diff --git a/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker.html b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker.html
new file mode 100644
index 0000000..d792ffc
--- /dev/null
+++ b/LayoutTests/http/tests/security/isolatedWorld/bypass-main-world-csp-worker.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+<!-- FIXME: Add child-src 'none' once we implement the child-src directive. -->
+<meta http-equiv="Content-Security-Policy" content="script-src 'unsafe-inline'">
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+</script>
+</head>
+<body>
+<p>This tests that in an isolated world the Content Security Policy of the parent origin (this page) is bypassed and a Web Worker is allowed to be instantiated with a script URL not listed in the CSP of the page.</p>
+<pre id="result"></pre>
+<script>
+window.onmessage = function (event)
+{
+    document.getElementById("result").textContent = event.data;
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+function runTest()
+{
+    var worker;
+    try {
+        worker = new Worker("http://127.0.0.1:8000/security/contentSecurityPolicy/resources/worker.php?type=alert-pass");
+        window.postMessage("PASS worker instantiated.", "*");
+    } catch (exception) {
+        window.postMessage("FAIL should not have thrown an exception when creating worker. Threw exception " + exception + ".", "*");
+    }
+}
+
+if (window.testRunner)
+    testRunner.evaluateScriptInIsolatedWorld(0, runTest.toString() + ";runTest();");
+</script>
+</body>
+</html>
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index e88cdfd..836414e 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,86 @@
+2016-02-07  Daniel Bates  <dabates@apple.com>
+
+        CSP: Allow Web Workers initiated from an isolated world to bypass the main world Content Security Policy
+        https://bugs.webkit.org/show_bug.cgi?id=153622
+        <rdar://problem/24400023>
+
+        Reviewed by Gavin Barraclough.
+
+        Fixes an issue where Web Workers initiated from an isolated world (say, a Safari Content Script Extension)
+        would be subject to the Content Security Policy of the page.
+
+        Currently code in an isolated world that does not execute in a Web Worker is exempt from the CSP of
+        the page. However, code that runs inside a Web Worker that was initiated from an isolated world is
+        subject to the CSP of the page. Instead, such Web Worker code should also be exempt from the CSP of
+        the page.
+
+        Tests: http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-eval.html
+               http/tests/security/isolatedWorld/bypass-main-world-csp-worker-blob-xhr.html
+               http/tests/security/isolatedWorld/bypass-main-world-csp-worker.html
+
+        * Modules/websockets/WebSocket.cpp:
+        (WebCore::WebSocket::connect): Modified to ask the script execution context whether to bypass the
+        main world Content Security Policy now that script execution context knows this information.
+        * bindings/js/ScriptController.cpp:
+        (WebCore::ScriptController::shouldBypassMainWorldContentSecurityPolicy): Deleted; moved logic from here...
+        * bindings/js/ScriptController.h:
+        * dom/Document.cpp:
+        (WebCore::Document::shouldBypassMainWorldContentSecurityPolicy): ...to here.
+        * dom/Document.h:
+        * dom/ScriptExecutionContext.h:
+        (WebCore::ScriptExecutionContext::shouldBypassMainWorldContentSecurityPolicy): Added; defaults to false -
+        do not bypass the main world Content Security Policy.
+        * page/EventSource.cpp:
+        (WebCore::EventSource::create): Modified to ask the script execution context whether to bypass the
+        main world Content Security Policy now that script execution context knows this information.
+        * page/csp/ContentSecurityPolicy.cpp:
+        (WebCore::ContentSecurityPolicy::shouldBypassMainWorldContentSecurityPolicy): Deleted.
+        * page/csp/ContentSecurityPolicy.h:
+        * workers/AbstractWorker.cpp:
+        (WebCore::AbstractWorker::resolveURL): Bypass the main world Content Security Policy if applicable.
+        Added FIXME comment to enforce the child-src directive of the document's CSP (as opposed to the script-src
+        directive) on the worker's script URL. Also, scriptExecutionContext()->contentSecurityPolicy() should
+        always be non-null just as we expect scriptExecutionContext()->securityOrigin() to be non-null. Assert
+        this invariant to catch cases where a ScriptExecutionContext is not properly initialized.
+        * workers/DedicatedWorkerGlobalScope.cpp:
+        (WebCore::DedicatedWorkerGlobalScope::create): Modified to take boolean argument shouldBypassMainWorldContentSecurityPolicy
+        as to whether to bypass the main world Content Security Policy and only apply the Content Security
+        Policy headers when shouldBypassMainWorldContentSecurityPolicy is false.
+        (WebCore::DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope): Pass through a boolean argument shouldBypassMainWorldContentSecurityPolicy
+        as to whether to bypass the main world Content Security Policy.
+        * workers/DedicatedWorkerGlobalScope.h:
+        * workers/DedicatedWorkerThread.cpp:
+        (WebCore::DedicatedWorkerThread::DedicatedWorkerThread): Ditto.
+        (WebCore::DedicatedWorkerThread::createWorkerGlobalScope): Ditto.
+        * workers/DedicatedWorkerThread.h:
+        * workers/Worker.cpp:
+        (WebCore::Worker::create): Store whether we should bypass the main world Content Security Policy so
+        that we can pass it to WorkerMessagingProxy::startWorkerGlobalScope() in Worker::notifyFinished().
+        We need to store this decision here as opposed to determining it at any later time (say, in Worker::notifyFinished())
+        because it is dependent on the current JavaScript program stack at the time this function is invoked.
+        (WebCore::Worker::notifyFinished): Pass whether to bypass the main world Content Security Policy.
+        * workers/Worker.h:
+        * workers/WorkerGlobalScope.cpp:
+        (WebCore::WorkerGlobalScope::WorkerGlobalScope): Modified to take a boolean as to whether to bypass the
+        main world Content Security Policy and store it in a member field. Also, always instantiate a Content
+        Security Policy object as our current code assumes that one is always created.
+        * workers/WorkerGlobalScope.h:
+        * workers/WorkerGlobalScopeProxy.h:
+        * workers/WorkerMessagingProxy.cpp:
+        (WebCore::WorkerMessagingProxy::startWorkerGlobalScope): Pass through a boolean argument shouldBypassMainWorldContentSecurityPolicy
+        as to whether to bypass the main world Content Security Policy.
+        * workers/WorkerMessagingProxy.h:
+        * workers/WorkerThread.cpp:
+        (WebCore::WorkerThreadStartupData::WorkerThreadStartupData): Modified to take a boolean argument as to
+        whether to bypass the main world Content Security Policy and store it in a member field.
+        (WebCore::WorkerThread::WorkerThread): Pass through a boolean argument shouldBypassMainWorldContentSecurityPolicy
+        as to whether to bypass the main world Content Security Policy.
+        (WebCore::WorkerThread::workerThread): Ditto.
+        * workers/WorkerThread.h:
+        * xml/XMLHttpRequest.cpp:
+        (WebCore::XMLHttpRequest::open): Modified to ask the script execution context whether to bypass the
+        main world Content Security Policy now that script execution context knows this information.
+
 2016-02-07  Dan Bernstein  <mitz@apple.com>
 
         [Cocoa] Replace __has_include guards around inclusion of Apple-internal-SDK headers with USE(APPLE_INTERNAL_SDK)
diff --git a/Source/WebCore/Modules/websockets/WebSocket.cpp b/Source/WebCore/Modules/websockets/WebSocket.cpp
index 08376de..13bb147 100644
--- a/Source/WebCore/Modules/websockets/WebSocket.cpp
+++ b/Source/WebCore/Modules/websockets/WebSocket.cpp
@@ -238,8 +238,7 @@
     }
 
     // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
-    bool shouldBypassMainWorldContentSecurityPolicy = ContentSecurityPolicy::shouldBypassMainWorldContentSecurityPolicy(*scriptExecutionContext());
-    if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(m_url, shouldBypassMainWorldContentSecurityPolicy)) {
+    if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(m_url, scriptExecutionContext()->shouldBypassMainWorldContentSecurityPolicy())) {
         m_state = CLOSED;
 
         // FIXME: Should this be throwing an exception?
diff --git a/Source/WebCore/bindings/js/ScriptController.cpp b/Source/WebCore/bindings/js/ScriptController.cpp
index 34e09e4..aae5c3e 100644
--- a/Source/WebCore/bindings/js/ScriptController.cpp
+++ b/Source/WebCore/bindings/js/ScriptController.cpp
@@ -519,17 +519,6 @@
     return evaluateInWorld(sourceCode, world);
 }
 
-bool ScriptController::shouldBypassMainWorldContentSecurityPolicy()
-{
-    CallFrame* callFrame = JSDOMWindow::commonVM().topCallFrame;
-    if (callFrame == CallFrame::noCaller()) 
-        return false;
-    DOMWrapperWorld& domWrapperWorld = currentWorld(callFrame);
-    if (domWrapperWorld.isNormal())
-        return false;
-    return true;
-}
-
 bool ScriptController::canExecuteScripts(ReasonForCallingCanExecuteScripts reason)
 {
     if (m_frame.document() && m_frame.document()->isSandboxed(SandboxScripts)) {
diff --git a/Source/WebCore/bindings/js/ScriptController.h b/Source/WebCore/bindings/js/ScriptController.h
index 2976fc3..62a51b8 100644
--- a/Source/WebCore/bindings/js/ScriptController.h
+++ b/Source/WebCore/bindings/js/ScriptController.h
@@ -166,8 +166,6 @@
     WEBCORE_EXPORT NPObject* windowScriptNPObject();
 #endif
 
-    bool shouldBypassMainWorldContentSecurityPolicy();
-
 private:
     WEBCORE_EXPORT JSDOMWindowShell* initScript(DOMWrapperWorld&);
 
diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp
index 37c6ebb..8fbab83 100644
--- a/Source/WebCore/dom/Document.cpp
+++ b/Source/WebCore/dom/Document.cpp
@@ -2431,6 +2431,17 @@
 #endif
 }
 
+bool Document::shouldBypassMainWorldContentSecurityPolicy() const
+{
+    JSC::CallFrame* callFrame = JSDOMWindow::commonVM().topCallFrame;
+    if (callFrame == JSC::CallFrame::noCaller())
+        return false;
+    DOMWrapperWorld& domWrapperWorld = currentWorld(callFrame);
+    if (domWrapperWorld.isNormal())
+        return false;
+    return true;
+}
+
 void Document::platformSuspendOrStopActiveDOMObjects()
 {
 #if PLATFORM(IOS)
diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h
index 72cbbcc..5f9c2a2 100644
--- a/Source/WebCore/dom/Document.h
+++ b/Source/WebCore/dom/Document.h
@@ -603,6 +603,7 @@
     void prepareForDestruction();
 
     // Override ScriptExecutionContext methods to do additional work
+    bool shouldBypassMainWorldContentSecurityPolicy() const override final;
     virtual void suspendActiveDOMObjects(ActiveDOMObject::ReasonForSuspension) override final;
     virtual void resumeActiveDOMObjects(ActiveDOMObject::ReasonForSuspension) override final;
     virtual void stopActiveDOMObjects() override final;
diff --git a/Source/WebCore/dom/ScriptExecutionContext.h b/Source/WebCore/dom/ScriptExecutionContext.h
index c1b1d0b..c6a9116 100644
--- a/Source/WebCore/dom/ScriptExecutionContext.h
+++ b/Source/WebCore/dom/ScriptExecutionContext.h
@@ -82,6 +82,8 @@
 
     virtual SecurityOrigin* topOrigin() const = 0;
 
+    virtual bool shouldBypassMainWorldContentSecurityPolicy() const { return false; }
+
     PublicURLManager& publicURLManager();
 
     // Active objects are not garbage collected even if inaccessible, e.g. because their activity may result in callbacks being invoked.
diff --git a/Source/WebCore/page/EventSource.cpp b/Source/WebCore/page/EventSource.cpp
index 5f6c8b5..2e619ea 100644
--- a/Source/WebCore/page/EventSource.cpp
+++ b/Source/WebCore/page/EventSource.cpp
@@ -85,8 +85,7 @@
     }
 
     // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
-    bool shouldBypassMainWorldContentSecurityPolicy = ContentSecurityPolicy::shouldBypassMainWorldContentSecurityPolicy(context);
-    if (!context.contentSecurityPolicy()->allowConnectToSource(fullURL, shouldBypassMainWorldContentSecurityPolicy)) {
+    if (!context.contentSecurityPolicy()->allowConnectToSource(fullURL, context.shouldBypassMainWorldContentSecurityPolicy())) {
         // FIXME: Should this be throwing an exception?
         ec = SECURITY_ERR;
         return nullptr;
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
index b6012d3..48ec135 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
+++ b/Source/WebCore/page/csp/ContentSecurityPolicy.cpp
@@ -1775,15 +1775,5 @@
     return false;
 #endif
 }
-
-bool ContentSecurityPolicy::shouldBypassMainWorldContentSecurityPolicy(ScriptExecutionContext& context)
-{
-    if (is<Document>(context)) {
-        auto& document = downcast<Document>(context);
-        return document.frame() && document.frame()->script().shouldBypassMainWorldContentSecurityPolicy();
-    }
-    
-    return false;
-}
     
 }
diff --git a/Source/WebCore/page/csp/ContentSecurityPolicy.h b/Source/WebCore/page/csp/ContentSecurityPolicy.h
index d94272d..9817a49 100644
--- a/Source/WebCore/page/csp/ContentSecurityPolicy.h
+++ b/Source/WebCore/page/csp/ContentSecurityPolicy.h
@@ -102,8 +102,6 @@
 
     bool experimentalFeaturesEnabled() const;
 
-    static bool shouldBypassMainWorldContentSecurityPolicy(ScriptExecutionContext&);
-
     // The following functions are used by internal data structures to call back into this object when parsing, validating,
     // and applying a Content Security Policy.
     // FIXME: We should make the various directives serve only as state stores for the parsed policy and remove these functions.
diff --git a/Source/WebCore/workers/AbstractWorker.cpp b/Source/WebCore/workers/AbstractWorker.cpp
index 801c8ef..398e764 100644
--- a/Source/WebCore/workers/AbstractWorker.cpp
+++ b/Source/WebCore/workers/AbstractWorker.cpp
@@ -62,7 +62,10 @@
         return URL();
     }
 
-    if (scriptExecutionContext()->contentSecurityPolicy() && !scriptExecutionContext()->contentSecurityPolicy()->allowScriptFromSource(scriptURL)) {
+    // FIXME: Enforce the child-src directive instead of script-src per <https://w3c.github.io/webappsec-csp/2/#directive-child-src-workers> (29 August 2015).
+    // See <https://bugs.webkit.org/show_bug.cgi?id=153562>.
+    ASSERT(scriptExecutionContext()->contentSecurityPolicy());
+    if (!scriptExecutionContext()->contentSecurityPolicy()->allowScriptFromSource(scriptURL, scriptExecutionContext()->shouldBypassMainWorldContentSecurityPolicy())) {
         ec = SECURITY_ERR;
         return URL();
     }
diff --git a/Source/WebCore/workers/DedicatedWorkerGlobalScope.cpp b/Source/WebCore/workers/DedicatedWorkerGlobalScope.cpp
index 91c7f23..30fde1c 100644
--- a/Source/WebCore/workers/DedicatedWorkerGlobalScope.cpp
+++ b/Source/WebCore/workers/DedicatedWorkerGlobalScope.cpp
@@ -40,15 +40,16 @@
 
 namespace WebCore {
 
-Ref<DedicatedWorkerGlobalScope> DedicatedWorkerGlobalScope::create(const URL& url, const String& userAgent, DedicatedWorkerThread& thread, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, PassRefPtr<SecurityOrigin> topOrigin)
+Ref<DedicatedWorkerGlobalScope> DedicatedWorkerGlobalScope::create(const URL& url, const String& userAgent, DedicatedWorkerThread& thread, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, PassRefPtr<SecurityOrigin> topOrigin)
 {
-    Ref<DedicatedWorkerGlobalScope> context = adoptRef(*new DedicatedWorkerGlobalScope(url, userAgent, thread, topOrigin));
-    context->applyContentSecurityPolicyResponseHeaders(contentSecurityPolicyResponseHeaders);
+    Ref<DedicatedWorkerGlobalScope> context = adoptRef(*new DedicatedWorkerGlobalScope(url, userAgent, thread, shouldBypassMainWorldContentSecurityPolicy, topOrigin));
+    if (!shouldBypassMainWorldContentSecurityPolicy)
+        context->applyContentSecurityPolicyResponseHeaders(contentSecurityPolicyResponseHeaders);
     return context;
 }
 
-DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(const URL& url, const String& userAgent, DedicatedWorkerThread& thread, PassRefPtr<SecurityOrigin> topOrigin)
-    : WorkerGlobalScope(url, userAgent, thread, topOrigin)
+DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(const URL& url, const String& userAgent, DedicatedWorkerThread& thread, bool shouldBypassMainWorldContentSecurityPolicy, PassRefPtr<SecurityOrigin> topOrigin)
+    : WorkerGlobalScope(url, userAgent, thread, shouldBypassMainWorldContentSecurityPolicy, topOrigin)
 {
 }
 
diff --git a/Source/WebCore/workers/DedicatedWorkerGlobalScope.h b/Source/WebCore/workers/DedicatedWorkerGlobalScope.h
index 29b722a..03155f3 100644
--- a/Source/WebCore/workers/DedicatedWorkerGlobalScope.h
+++ b/Source/WebCore/workers/DedicatedWorkerGlobalScope.h
@@ -42,7 +42,7 @@
     class DedicatedWorkerGlobalScope : public WorkerGlobalScope {
     public:
         typedef WorkerGlobalScope Base;
-        static Ref<DedicatedWorkerGlobalScope> create(const URL&, const String& userAgent, DedicatedWorkerThread&, const ContentSecurityPolicyResponseHeaders&, PassRefPtr<SecurityOrigin> topOrigin);
+        static Ref<DedicatedWorkerGlobalScope> create(const URL&, const String& userAgent, DedicatedWorkerThread&, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, PassRefPtr<SecurityOrigin> topOrigin);
         virtual ~DedicatedWorkerGlobalScope();
 
         virtual bool isDedicatedWorkerGlobalScope() const override { return true; }
@@ -60,7 +60,7 @@
         DedicatedWorkerThread& thread();
 
     private:
-        DedicatedWorkerGlobalScope(const URL&, const String& userAgent, DedicatedWorkerThread&, PassRefPtr<SecurityOrigin> topOrigin);
+        DedicatedWorkerGlobalScope(const URL&, const String& userAgent, DedicatedWorkerThread&, bool shouldBypassMainWorldContentSecurityPolicy, PassRefPtr<SecurityOrigin> topOrigin);
     };
 
 } // namespace WebCore
diff --git a/Source/WebCore/workers/DedicatedWorkerThread.cpp b/Source/WebCore/workers/DedicatedWorkerThread.cpp
index 3604bf8..0394f0d 100644
--- a/Source/WebCore/workers/DedicatedWorkerThread.cpp
+++ b/Source/WebCore/workers/DedicatedWorkerThread.cpp
@@ -38,8 +38,8 @@
 
 namespace WebCore {
 
-DedicatedWorkerThread::DedicatedWorkerThread(const URL& url, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerObjectProxy& workerObjectProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, const SecurityOrigin* topOrigin)
-    : WorkerThread(url, userAgent, sourceCode, workerLoaderProxy, workerObjectProxy, startMode, contentSecurityPolicyResponseHeaders, topOrigin)
+DedicatedWorkerThread::DedicatedWorkerThread(const URL& url, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerObjectProxy& workerObjectProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin)
+    : WorkerThread(url, userAgent, sourceCode, workerLoaderProxy, workerObjectProxy, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, topOrigin)
     , m_workerObjectProxy(workerObjectProxy)
 {
 }
@@ -48,9 +48,9 @@
 {
 }
 
-Ref<WorkerGlobalScope> DedicatedWorkerThread::createWorkerGlobalScope(const URL& url, const String& userAgent, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, PassRefPtr<SecurityOrigin> topOrigin)
+Ref<WorkerGlobalScope> DedicatedWorkerThread::createWorkerGlobalScope(const URL& url, const String& userAgent, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, PassRefPtr<SecurityOrigin> topOrigin)
 {
-    return DedicatedWorkerGlobalScope::create(url, userAgent, *this, contentSecurityPolicyResponseHeaders, topOrigin);
+    return DedicatedWorkerGlobalScope::create(url, userAgent, *this, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, topOrigin);
 }
 
 void DedicatedWorkerThread::runEventLoop()
diff --git a/Source/WebCore/workers/DedicatedWorkerThread.h b/Source/WebCore/workers/DedicatedWorkerThread.h
index 89d88f2..9d7ef0f 100644
--- a/Source/WebCore/workers/DedicatedWorkerThread.h
+++ b/Source/WebCore/workers/DedicatedWorkerThread.h
@@ -48,11 +48,11 @@
         WorkerObjectProxy& workerObjectProxy() const { return m_workerObjectProxy; }
 
     protected:
-        virtual Ref<WorkerGlobalScope> createWorkerGlobalScope(const URL&, const String& userAgent, const ContentSecurityPolicyResponseHeaders&, PassRefPtr<SecurityOrigin> topOrigin) override;
+        virtual Ref<WorkerGlobalScope> createWorkerGlobalScope(const URL&, const String& userAgent, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, PassRefPtr<SecurityOrigin> topOrigin) override;
         virtual void runEventLoop() override;
 
     private:
-        DedicatedWorkerThread(const URL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerObjectProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, const SecurityOrigin* topOrigin);
+        DedicatedWorkerThread(const URL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerObjectProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin);
 
         WorkerObjectProxy& m_workerObjectProxy;
     };
diff --git a/Source/WebCore/workers/Worker.cpp b/Source/WebCore/workers/Worker.cpp
index 910dd8b..ac4eb4a 100644
--- a/Source/WebCore/workers/Worker.cpp
+++ b/Source/WebCore/workers/Worker.cpp
@@ -87,6 +87,8 @@
     if (scriptURL.isEmpty())
         return nullptr;
 
+    worker->m_shouldBypassMainWorldContentSecurityPolicy = context.shouldBypassMainWorldContentSecurityPolicy();
+
     // The worker context does not exist while loading, so we must ensure that the worker object is not collected, nor are its event listeners.
     worker->setPendingActivity(worker.ptr());
 
@@ -166,7 +168,7 @@
         dispatchEvent(Event::create(eventNames().errorEvent, false, true));
     else {
         const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders = m_contentSecurityPolicyResponseHeaders ? m_contentSecurityPolicyResponseHeaders.value() : scriptExecutionContext()->contentSecurityPolicy()->responseHeaders();
-        m_contextProxy->startWorkerGlobalScope(m_scriptLoader->url(), scriptExecutionContext()->userAgent(m_scriptLoader->url()), m_scriptLoader->script(), contentSecurityPolicyResponseHeaders, DontPauseWorkerGlobalScopeOnStart);
+        m_contextProxy->startWorkerGlobalScope(m_scriptLoader->url(), scriptExecutionContext()->userAgent(m_scriptLoader->url()), m_scriptLoader->script(), contentSecurityPolicyResponseHeaders, m_shouldBypassMainWorldContentSecurityPolicy, DontPauseWorkerGlobalScopeOnStart);
         InspectorInstrumentation::scriptImported(scriptExecutionContext(), m_scriptLoader->identifier(), m_scriptLoader->script());
     }
     m_scriptLoader = nullptr;
diff --git a/Source/WebCore/workers/Worker.h b/Source/WebCore/workers/Worker.h
index cd3d111..64756e9 100644
--- a/Source/WebCore/workers/Worker.h
+++ b/Source/WebCore/workers/Worker.h
@@ -86,6 +86,7 @@
         RefPtr<WorkerScriptLoader> m_scriptLoader;
         WorkerGlobalScopeProxy* m_contextProxy; // The proxy outlives the worker to perform thread shutdown.
         Optional<ContentSecurityPolicyResponseHeaders> m_contentSecurityPolicyResponseHeaders;
+        bool m_shouldBypassMainWorldContentSecurityPolicy { false };
     };
 
 } // namespace WebCore
diff --git a/Source/WebCore/workers/WorkerGlobalScope.cpp b/Source/WebCore/workers/WorkerGlobalScope.cpp
index 67c6dfe..c4a2c0e 100644
--- a/Source/WebCore/workers/WorkerGlobalScope.cpp
+++ b/Source/WebCore/workers/WorkerGlobalScope.cpp
@@ -62,12 +62,13 @@
 
 namespace WebCore {
 
-WorkerGlobalScope::WorkerGlobalScope(const URL& url, const String& userAgent, WorkerThread& thread, PassRefPtr<SecurityOrigin> topOrigin)
+WorkerGlobalScope::WorkerGlobalScope(const URL& url, const String& userAgent, WorkerThread& thread, bool shouldBypassMainWorldContentSecurityPolicy, PassRefPtr<SecurityOrigin> topOrigin)
     : m_url(url)
     , m_userAgent(userAgent)
     , m_script(std::make_unique<WorkerScriptController>(this))
     , m_thread(thread)
     , m_closing(false)
+    , m_shouldBypassMainWorldContentSecurityPolicy(shouldBypassMainWorldContentSecurityPolicy)
     , m_eventQueue(*this)
     , m_topOrigin(topOrigin)
 {
diff --git a/Source/WebCore/workers/WorkerGlobalScope.h b/Source/WebCore/workers/WorkerGlobalScope.h
index d4db351..89a5d22 100644
--- a/Source/WebCore/workers/WorkerGlobalScope.h
+++ b/Source/WebCore/workers/WorkerGlobalScope.h
@@ -67,6 +67,8 @@
 
         virtual void disableEval(const String& errorMessage) override;
 
+        bool shouldBypassMainWorldContentSecurityPolicy() const override final { return m_shouldBypassMainWorldContentSecurityPolicy; }
+
         WorkerScriptController* script() { return m_script.get(); }
         void clearScript() { m_script = nullptr; }
 
@@ -130,7 +132,7 @@
 #endif
 
     protected:
-        WorkerGlobalScope(const URL&, const String& userAgent, WorkerThread&, PassRefPtr<SecurityOrigin> topOrigin);
+        WorkerGlobalScope(const URL&, const String& userAgent, WorkerThread&, bool shouldBypassMainWorldContentSecurityPolicy, PassRefPtr<SecurityOrigin> topOrigin);
         void applyContentSecurityPolicyResponseHeaders(const ContentSecurityPolicyResponseHeaders&);
 
         virtual void logExceptionToConsole(const String& errorMessage, const String& sourceURL, int lineNumber, int columnNumber, RefPtr<Inspector::ScriptCallStack>&&) override;
@@ -159,6 +161,7 @@
         WorkerThread& m_thread;
 
         bool m_closing;
+        bool m_shouldBypassMainWorldContentSecurityPolicy;
 
         HashSet<Observer*> m_workerObservers;
 
diff --git a/Source/WebCore/workers/WorkerGlobalScopeProxy.h b/Source/WebCore/workers/WorkerGlobalScopeProxy.h
index 6bd88c4..cdb1746 100644
--- a/Source/WebCore/workers/WorkerGlobalScopeProxy.h
+++ b/Source/WebCore/workers/WorkerGlobalScopeProxy.h
@@ -49,7 +49,7 @@
 
         virtual ~WorkerGlobalScopeProxy() { }
 
-        virtual void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, WorkerThreadStartMode) = 0;
+        virtual void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, WorkerThreadStartMode) = 0;
 
         virtual void terminateWorkerGlobalScope() = 0;
 
diff --git a/Source/WebCore/workers/WorkerMessagingProxy.cpp b/Source/WebCore/workers/WorkerMessagingProxy.cpp
index 699e9b7..82cd0bc 100644
--- a/Source/WebCore/workers/WorkerMessagingProxy.cpp
+++ b/Source/WebCore/workers/WorkerMessagingProxy.cpp
@@ -72,12 +72,12 @@
         || (is<WorkerGlobalScope>(*m_scriptExecutionContext) && currentThread() == downcast<WorkerGlobalScope>(*m_scriptExecutionContext).thread().threadID()));
 }
 
-void WorkerMessagingProxy::startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, WorkerThreadStartMode startMode)
+void WorkerMessagingProxy::startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, WorkerThreadStartMode startMode)
 {
     // FIXME: This need to be revisited when we support nested worker one day
     ASSERT(m_scriptExecutionContext);
     Document& document = downcast<Document>(*m_scriptExecutionContext);
-    RefPtr<DedicatedWorkerThread> thread = DedicatedWorkerThread::create(scriptURL, userAgent, sourceCode, *this, *this, startMode, contentSecurityPolicyResponseHeaders, document.topOrigin());
+    RefPtr<DedicatedWorkerThread> thread = DedicatedWorkerThread::create(scriptURL, userAgent, sourceCode, *this, *this, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, document.topOrigin());
     workerThreadCreated(thread);
     thread->start();
 }
diff --git a/Source/WebCore/workers/WorkerMessagingProxy.h b/Source/WebCore/workers/WorkerMessagingProxy.h
index aa5b891..dd5c05ce 100644
--- a/Source/WebCore/workers/WorkerMessagingProxy.h
+++ b/Source/WebCore/workers/WorkerMessagingProxy.h
@@ -52,7 +52,7 @@
 
         // Implementations of WorkerGlobalScopeProxy.
         // (Only use these methods in the worker object thread.)
-        virtual void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, WorkerThreadStartMode) override;
+        virtual void startWorkerGlobalScope(const URL& scriptURL, const String& userAgent, const String& sourceCode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, WorkerThreadStartMode) override;
         virtual void terminateWorkerGlobalScope() override;
         virtual void postMessageToWorkerGlobalScope(PassRefPtr<SerializedScriptValue>, std::unique_ptr<MessagePortChannelArray>) override;
         virtual bool hasPendingActivity() const override;
diff --git a/Source/WebCore/workers/WorkerThread.cpp b/Source/WebCore/workers/WorkerThread.cpp
index 8122380..297bf7e6 100644
--- a/Source/WebCore/workers/WorkerThread.cpp
+++ b/Source/WebCore/workers/WorkerThread.cpp
@@ -70,31 +70,33 @@
 struct WorkerThreadStartupData {
     WTF_MAKE_NONCOPYABLE(WorkerThreadStartupData); WTF_MAKE_FAST_ALLOCATED;
 public:
-    WorkerThreadStartupData(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, const SecurityOrigin* topOrigin);
+    WorkerThreadStartupData(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin);
 
     URL m_scriptURL;
     String m_userAgent;
     String m_sourceCode;
     WorkerThreadStartMode m_startMode;
     ContentSecurityPolicyResponseHeaders m_contentSecurityPolicyResponseHeaders;
+    bool m_shouldBypassMainWorldContentSecurityPolicy;
     RefPtr<SecurityOrigin> m_topOrigin;
 };
 
-WorkerThreadStartupData::WorkerThreadStartupData(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, const SecurityOrigin* topOrigin)
+WorkerThreadStartupData::WorkerThreadStartupData(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin)
     : m_scriptURL(scriptURL.isolatedCopy())
     , m_userAgent(userAgent.isolatedCopy())
     , m_sourceCode(sourceCode.isolatedCopy())
     , m_startMode(startMode)
     , m_contentSecurityPolicyResponseHeaders(contentSecurityPolicyResponseHeaders.isolatedCopy())
+    , m_shouldBypassMainWorldContentSecurityPolicy(shouldBypassMainWorldContentSecurityPolicy)
     , m_topOrigin(topOrigin ? &topOrigin->isolatedCopy().get() : nullptr)
 {
 }
 
-WorkerThread::WorkerThread(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, const SecurityOrigin* topOrigin)
+WorkerThread::WorkerThread(const URL& scriptURL, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy, WorkerReportingProxy& workerReportingProxy, WorkerThreadStartMode startMode, const ContentSecurityPolicyResponseHeaders& contentSecurityPolicyResponseHeaders, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin)
     : m_threadID(0)
     , m_workerLoaderProxy(workerLoaderProxy)
     , m_workerReportingProxy(workerReportingProxy)
-    , m_startupData(std::make_unique<WorkerThreadStartupData>(scriptURL, userAgent, sourceCode, startMode, contentSecurityPolicyResponseHeaders, topOrigin))
+    , m_startupData(std::make_unique<WorkerThreadStartupData>(scriptURL, userAgent, sourceCode, startMode, contentSecurityPolicyResponseHeaders, shouldBypassMainWorldContentSecurityPolicy, topOrigin))
 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
     , m_notificationClient(0)
 #endif
@@ -144,7 +146,7 @@
 
     {
         LockHolder lock(m_threadCreationMutex);
-        m_workerGlobalScope = createWorkerGlobalScope(m_startupData->m_scriptURL, m_startupData->m_userAgent, m_startupData->m_contentSecurityPolicyResponseHeaders, m_startupData->m_topOrigin.release());
+        m_workerGlobalScope = createWorkerGlobalScope(m_startupData->m_scriptURL, m_startupData->m_userAgent, m_startupData->m_contentSecurityPolicyResponseHeaders, m_startupData->m_shouldBypassMainWorldContentSecurityPolicy, m_startupData->m_topOrigin.release());
 
         if (m_runLoop.terminated()) {
             // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet,
diff --git a/Source/WebCore/workers/WorkerThread.h b/Source/WebCore/workers/WorkerThread.h
index bb79582..16c8db7 100644
--- a/Source/WebCore/workers/WorkerThread.h
+++ b/Source/WebCore/workers/WorkerThread.h
@@ -68,10 +68,10 @@
 #endif
 
     protected:
-        WorkerThread(const URL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerReportingProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, const SecurityOrigin* topOrigin);
+        WorkerThread(const URL&, const String& userAgent, const String& sourceCode, WorkerLoaderProxy&, WorkerReportingProxy&, WorkerThreadStartMode, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, const SecurityOrigin* topOrigin);
 
         // Factory method for creating a new worker context for the thread.
-        virtual Ref<WorkerGlobalScope> createWorkerGlobalScope(const URL&, const String& userAgent, const ContentSecurityPolicyResponseHeaders&, PassRefPtr<SecurityOrigin> topOrigin) = 0;
+        virtual Ref<WorkerGlobalScope> createWorkerGlobalScope(const URL&, const String& userAgent, const ContentSecurityPolicyResponseHeaders&, bool shouldBypassMainWorldContentSecurityPolicy, PassRefPtr<SecurityOrigin> topOrigin) = 0;
 
         // Executes the event loop for the worker thread. Derived classes can override to perform actions before/after entering the event loop.
         virtual void runEventLoop();
diff --git a/Source/WebCore/xml/XMLHttpRequest.cpp b/Source/WebCore/xml/XMLHttpRequest.cpp
index 9d817e1..34aae824 100644
--- a/Source/WebCore/xml/XMLHttpRequest.cpp
+++ b/Source/WebCore/xml/XMLHttpRequest.cpp
@@ -498,8 +498,7 @@
     }
 
     // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved.
-    bool shouldBypassMainWorldContentSecurityPolicy = ContentSecurityPolicy::shouldBypassMainWorldContentSecurityPolicy(*scriptExecutionContext());
-    if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(url, shouldBypassMainWorldContentSecurityPolicy)) {
+    if (!scriptExecutionContext()->contentSecurityPolicy()->allowConnectToSource(url, scriptExecutionContext()->shouldBypassMainWorldContentSecurityPolicy())) {
         // FIXME: Should this be throwing an exception?
         ec = SECURITY_ERR;
         return;