blob: 897f86d4b2281669e93325837d21704b1da81bae [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/extension_apitest.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "extensions/common/manifest.h"
#include "extensions/test/result_catcher.h"
#include "extensions/test/test_extension_dir.h"
#include "net/dns/mock_host_resolver.h"
namespace extensions {
// Exercises CSP properties in "user-script" type extensions.
class UserScriptCspBrowserTest : public ExtensionApiTest {
public:
void SetUpOnMainThread() override {
ExtensionApiTest::SetUpOnMainThread();
host_resolver()->AddRule("*", "127.0.0.1");
ASSERT_TRUE(StartEmbeddedTestServer());
}
};
// Tests that the background service worker has its eval blocked by CSP.
IN_PROC_BROWSER_TEST_F(UserScriptCspBrowserTest, ServiceWorkerEvalBlocked) {
TestExtensionDir dir;
dir.WriteManifest(R"({
"name": "User Script CSP SW Test",
"manifest_version": 3,
"version": "1.0",
"converted_from_user_script": true,
"background": {
"service_worker": "sw.js"
}
})");
dir.WriteFile(FILE_PATH_LITERAL("sw.js"), R"(
try {
eval('self.foo = 3;');
chrome.test.fail('Unexpected val success');
} catch(e) {
if (e.message.includes('Content Security Policy')) {
chrome.test.succeed();
} else {
chrome.test.fail(`Unexpected eval failure: ${e.message}`);
}
}
)");
ResultCatcher result_catcher;
const Extension* extension = LoadExtension(dir.UnpackedPath());
ASSERT_TRUE(extension);
ASSERT_EQ(Manifest::Type::kUserScript, extension->GetType());
ASSERT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
// Tests that an extension page has its eval blocked by CSP.
IN_PROC_BROWSER_TEST_F(UserScriptCspBrowserTest, ExtensionPageEvalBlocked) {
TestExtensionDir dir;
dir.WriteManifest(R"({
"name": "User Script CSP Page Test",
"manifest_version": 3,
"version": "1.0",
"converted_from_user_script": true
})");
dir.WriteFile(FILE_PATH_LITERAL("page.html"), R"(
<html>
<head>
<script src="page.js"></script>
</head>
<body>Page</body>
</html>
)");
dir.WriteFile(FILE_PATH_LITERAL("page.js"), R"(
window.onload = function() {
try {
eval('window.foo = 3;');
chrome.test.fail('Unexpected eval success');
} catch(e) {
if (e.message.includes('Content Security Policy')) {
chrome.test.succeed();
} else {
chrome.test.fail(`Unexpected eval failure: ${e.message}`);
}
}
};
)");
const Extension* extension = LoadExtension(dir.UnpackedPath());
ASSERT_TRUE(extension);
ASSERT_EQ(Manifest::Type::kUserScript, extension->GetType());
ResultCatcher result_catcher;
content::WebContents* web_contents = GetActiveWebContents();
GURL page_url = extension->GetResourceURL("page.html");
ASSERT_TRUE(NavigateToURL(web_contents, page_url));
ASSERT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
// Tests that a content script has its eval blocked by isolated world CSP.
IN_PROC_BROWSER_TEST_F(UserScriptCspBrowserTest, ContentScriptEvalBlocked) {
TestExtensionDir dir;
dir.WriteManifest(R"({
"name": "User Script CSP CS Test",
"manifest_version": 3,
"version": "1.0",
"converted_from_user_script": true,
"content_scripts": [{
"matches": ["*://*/*"],
"js": ["content_script.js"]
}]
})");
dir.WriteFile(FILE_PATH_LITERAL("content_script.js"), R"(
try {
eval('window.foo = 3;');
chrome.test.fail('Unexpected eval success');
} catch(e) {
if (e.message.includes('Content Security Policy')) {
chrome.test.succeed();
} else {
chrome.test.fail(`Unexpected eval failure: ${e.message}`);
}
}
)");
const Extension* extension = LoadExtension(dir.UnpackedPath());
ASSERT_TRUE(extension);
ASSERT_EQ(Manifest::Type::kUserScript, extension->GetType());
GURL test_url = embedded_test_server()->GetURL("example.com", "/empty.html");
content::WebContents* web_contents = GetActiveWebContents();
ResultCatcher result_catcher;
ASSERT_TRUE(NavigateToURL(web_contents, test_url));
ASSERT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
} // namespace extensions