tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit b5afcc29507d3e84f61f27e26038f1393c4472a5
parent 9586335e869ce3552e48d0ea844496489b574ffd
Author: Yoshi Cheng-Hao Huang <allstars.chh@gmail.com>
Date:   Fri, 17 Oct 2025 20:06:50 +0000

Bug 1988419 - No need to check document's CSP for WebExtensions. r=robwu

WebExtensions shouldn't be restricted by the document's CSP.

Differential Revision: https://phabricator.services.mozilla.com/D265237

Diffstat:
Mdom/script/ModuleLoader.cpp | 25+++++++++++++------------
Mtoolkit/components/extensions/test/xpcshell/test_ext_contentscript_module_import.js | 43+++++++++++++++++++++++++++++++++++++++++++
Mtoolkit/components/extensions/test/xpcshell/test_ext_sandboxed_resource.js | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 122 insertions(+), 12 deletions(-)

diff --git a/dom/script/ModuleLoader.cpp b/dom/script/ModuleLoader.cpp @@ -69,19 +69,20 @@ bool ModuleLoader::CanStartLoad(ModuleLoadRequest* aRequest, nsresult* aRvOut) { return false; } - // If this document is sandboxed without 'allow-scripts', abort. - if (GetScriptLoader()->GetDocument()->HasScriptsBlockedBySandbox()) { - *aRvOut = NS_OK; - return false; - } - - // To prevent dynamic code execution, content scripts can only - // load moz-extension URLs. nsCOMPtr<nsIPrincipal> principal = aRequest->TriggeringPrincipal(); - if (BasePrincipal::Cast(principal)->ContentScriptAddonPolicy() && - !aRequest->mURI->SchemeIs("moz-extension")) { - *aRvOut = NS_ERROR_DOM_WEBEXT_CONTENT_SCRIPT_URI; - return false; + if (BasePrincipal::Cast(principal)->ContentScriptAddonPolicy()) { + // To prevent dynamic code execution, content scripts can only + // load moz-extension URLs. + if (!aRequest->mURI->SchemeIs("moz-extension")) { + *aRvOut = NS_ERROR_DOM_WEBEXT_CONTENT_SCRIPT_URI; + return false; + } + } else { + // If this document is sandboxed without 'allow-scripts', abort. + if (GetScriptLoader()->GetDocument()->HasScriptsBlockedBySandbox()) { + *aRvOut = NS_ERROR_CONTENT_BLOCKED; + return false; + } } if (LOG_ENABLED()) { diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_module_import.js b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_module_import.js @@ -11,6 +11,13 @@ server.registerPathHandler("/dummy", (request, response) => { response.write("<!DOCTYPE html><html></html>"); }); +server.registerPathHandler("/sandbox.html", (request, response) => { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/html", false); + response.setHeader("Content-Security-Policy", "sandbox allow-same-origin;"); + response.write(`<!DOCTYPE html><html> </html>`); +}); + server.registerPathHandler("/script.js", () => { ok(false, "Unexpected request to /script.js"); }); @@ -72,6 +79,42 @@ add_task(async function test_disallowed_import() { await contentPage.close(); }); +// The document's CSP shouldn't restrict the extension. +add_task(async function test_import_in_sandboxed_document() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + content_scripts: [ + { + matches: ["http://example.com/sandbox.html"], + js: ["main.js"], + }, + ], + }, + + files: { + "main.js": async function () { + try { + let mod = await import(browser.runtime.getURL("module2.js")); + browser.test.assertEq(mod.foo, 2); + } catch (e) { + browser.test.assertTrue(false, `Threw while importing module: ${e}`); + } + + browser.test.sendMessage("done"); + }, + "module2.js": MODULE2, + }, + }); + + await extension.startup(); + let contentPage = await ExtensionTestUtils.loadContentPage( + "http://example.com/sandbox.html" + ); + await extension.awaitMessage("done"); + await extension.unload(); + await contentPage.close(); +}); + add_task(async function test_import_non_web_accessible_non_strict() { // "non_strict" in the function name is referring to this pref. Setting it // to 'false' should allow MV2 extensions to dynamically load content diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_sandboxed_resource.js b/toolkit/components/extensions/test/xpcshell/test_ext_sandboxed_resource.js @@ -53,3 +53,69 @@ add_task(async function test_webext_background_sandbox_privileges() { await extension.awaitFinish("webext-background-sandbox-privileges"); await extension.unload(); }); + +add_task(async function test_webext_background_sandbox_iframe_import() { + function backgroundSubframeScript() { + document.title = "script_ran"; + import("./module1.js"); + } + + function backgroundScript() { + window.onload = () => { + browser.test.assertEq( + "script_ran", + frames[0].document.title, + "Sandbox with allow-scripts executes" + ); + + browser.test.assertEq( + "Initial title", + frames[1].document.title, + "Sandbox without allow-scripts does not run" + ); + browser.test.sendMessage("background_done"); + }; + } + + const MODULE1 = `browser.test.sendMessage("module_done")`; + + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + background: { + page: "background.html", + }, + }, + + files: { + "background.html": `<!DOCTYPE> + <html> + <head> + <meta charset="utf-8"> + </head> + <body> + <script src="background.js"><\/script> + <iframe src="background-subframe.html" sandbox="allow-same-origin allow-scripts"></iframe> + <iframe src="background-subframe.html" sandbox="allow-same-origin"></iframe> + </body> + </html>`, + "background-subframe.html": `<!DOCTYPE> + <html> + <title>Initial title</title> + <head> + <meta charset="utf-8"> + <script src="background-subframe.js"><\/script> + </head> + </html>`, + "background-subframe.js": backgroundSubframeScript, + "background.js": backgroundScript, + "module1.js": MODULE1, + }, + }); + + await extension.startup(); + await Promise.all([ + extension.awaitMessage("background_done"), + extension.awaitMessage("module_done"), + ]); + await extension.unload(); +});