diff --git a/shell/common/node_bindings.cc b/shell/common/node_bindings.cc index 28447a2775..ca65a4fd6d 100644 --- a/shell/common/node_bindings.cc +++ b/shell/common/node_bindings.cc @@ -184,9 +184,10 @@ v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings( v8::Local context, v8::Local source, bool is_code_like) { - // If we're running with contextIsolation enabled in the renderer process, - // fall back to Blink's logic. if (node::Environment::GetCurrent(context) == nullptr) { + // No node environment means we're in the renderer process, either in a + // sandboxed renderer or in an unsandboxed renderer with context isolation + // enabled. if (gin_helper::Locker::IsBrowserProcess()) { NOTREACHED(); return {false, {}}; @@ -195,6 +196,22 @@ v8::ModifyCodeGenerationFromStringsResult ModifyCodeGenerationFromStrings( context, source, is_code_like); } + // If we get here then we have a node environment, so either a) we're in the + // main process, or b) we're in the renderer process in a context that has + // both node and blink, i.e. contextIsolation disabled. + + // If we're in the main process, delegate to node. + if (gin_helper::Locker::IsBrowserProcess()) { + return node::ModifyCodeGenerationFromStrings(context, source, is_code_like); + } + + // If we're in the renderer with contextIsolation disabled, ask blink first + // (for CSP), and iff that allows codegen, delegate to node. + v8::ModifyCodeGenerationFromStringsResult result = + blink::V8Initializer::CodeGenerationCheckCallbackInMainThread( + context, source, is_code_like); + if (!result.codegen_allowed) + return result; return node::ModifyCodeGenerationFromStrings(context, source, is_code_like); } diff --git a/spec/chromium-spec.ts b/spec/chromium-spec.ts index cc3fa6a3ac..3453afa0d3 100644 --- a/spec/chromium-spec.ts +++ b/spec/chromium-spec.ts @@ -352,28 +352,74 @@ describe('web security', () => { }); }); - describe('csp in sandbox: false', () => { - it('is correctly applied', async () => { - const w = new BrowserWindow({ - show: false, - webPreferences: { sandbox: false } + describe('csp', () => { + for (const sandbox of [true, false]) { + describe(`when sandbox: ${sandbox}`, () => { + for (const contextIsolation of [true, false]) { + describe(`when contextIsolation: ${contextIsolation}`, () => { + it('prevents eval from running in an inline script', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { sandbox, contextIsolation } + }); + w.loadURL(`data:text/html, + + + `); + const [,, message] = await once(w.webContents, 'console-message'); + expect(message).to.match(/Refused to evaluate a string/); + }); + + it('does not prevent eval from running in an inline script when there is no csp', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { sandbox, contextIsolation } + }); + w.loadURL(`data:text/html, + `); + const [,, message] = await once(w.webContents, 'console-message'); + expect(message).to.equal('true'); + }); + + it('prevents eval from running in executeJavaScript', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { sandbox, contextIsolation } + }); + w.loadURL('data:text/html,'); + await expect(w.webContents.executeJavaScript('eval("true")')).to.be.rejected(); + }); + + it('does not prevent eval from running in executeJavaScript when there is no csp', async () => { + const w = new BrowserWindow({ + show: false, + webPreferences: { sandbox, contextIsolation } + }); + w.loadURL('data:text/html,'); + expect(await w.webContents.executeJavaScript('eval("true")')).to.be.true(); + }); + }); + } }); - w.loadURL(`data:text/html, - - - `); - const [,, message] = await once(w.webContents, 'console-message'); - expect(message).to.equal('success'); - }); + } }); it('does not crash when multiple WebContent are created with web security disabled', () => {