CVE-2026-11048
Overview
Files Changed
extensions/common/csp_validator.ccextensions/common/csp_validator_unittest.cc
Patch
From cd3b45a73d09a3fd98730133999fc6942aca83d9 Mon Sep 17 00:00:00 2001 From: Mike West <[email protected]> Date: Tue, 07 Apr 2026 23:54:00 -0700 Subject: [PATCH] Adjust extensions' CSP parser's whitespace list. Infra and CSP have aligned on a list of whitespace characters that slightly varies from what the extension parser is using. This patch adjusts extensions' parser's understanding to match the spec and other parts of Chromium. https://w3c.github.io/webappsec-csp/#framework-infrastructure https://infra.spec.whatwg.org/#ascii-whitespace Bug: 498808432 Change-Id: I88eff0ad86632a59479f1dfd124db092e82f8bfc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7724881 Commit-Queue: Mike West <[email protected]> Reviewed-by: Finnur Thorarinsson <[email protected]> Cr-Commit-Position: refs/heads/main@{#1611256} --- diff --git a/extensions/common/csp_validator.cc b/extensions/common/csp_validator.cc index a504211..11fa4ada 100644 --- a/extensions/common/csp_validator.cc +++ b/extensions/common/csp_validator.cc @@ -69,9 +69,8 @@ "'sha512-" }; -// TODO(karandeepb): This is not the same list as used by the CSP spec. See // https://infra.spec.whatwg.org/#ascii-whitespace. -const char kWhitespaceDelimiters[] = " \t\r\n"; +const char kWhitespaceDelimiters[] = " \t\r\n\f"; constexpr char kChromeResourcesUrl[] = "chrome://resources"; diff --git a/extensions/common/csp_validator_unittest.cc b/extensions/common/csp_validator_unittest.cc index f1f2c9e..15c3499 100644 --- a/extensions/common/csp_validator_unittest.cc +++ b/extensions/common/csp_validator_unittest.cc @@ -457,10 +457,14 @@ // Additional sandbox tokens are OK. EXPECT_TRUE(ContentSecurityPolicyIsSandboxed("sandbox allow-scripts", Manifest::Type::kExtension)); - // Except for allow-same-origin. + // Except for allow-same-origin... EXPECT_FALSE(ContentSecurityPolicyIsSandboxed("sandbox allow-same-origin", Manifest::Type::kExtension)); + // ... even if obscured. + EXPECT_FALSE(ContentSecurityPolicyIsSandboxed("sandbox allow-same-origin\fa", + Manifest::Type::kExtension)); + // Additional directives are OK. EXPECT_TRUE(ContentSecurityPolicyIsSandboxed( "sandbox; img-src https://google.com", Manifest::Type::kExtension));
Regression Test / PoC
diff --git a/extensions/common/csp_validator_unittest.cc b/extensions/common/csp_validator_unittest.cc
index f1f2c9e..15c3499 100644
--- a/extensions/common/csp_validator_unittest.cc
+++ b/extensions/common/csp_validator_unittest.cc
@@ -457,10 +457,14 @@
// Additional sandbox tokens are OK.
EXPECT_TRUE(ContentSecurityPolicyIsSandboxed("sandbox allow-scripts",
Manifest::Type::kExtension));
- // Except for allow-same-origin.
+ // Except for allow-same-origin...
EXPECT_FALSE(ContentSecurityPolicyIsSandboxed("sandbox allow-same-origin",
Manifest::Type::kExtension));
+ // ... even if obscured.
+ EXPECT_FALSE(ContentSecurityPolicyIsSandboxed("sandbox allow-same-origin\fa",
+ Manifest::Type::kExtension));
+
// Additional directives are OK.
EXPECT_TRUE(ContentSecurityPolicyIsSandboxed(
"sandbox; img-src https://google.com", Manifest::Type::kExtension));
Original Bug Report
Extension Sandbox CSP bypass via form-feed parser differential
Project Fortify, an experimental security project, has identified the following potential security issue. If you’re a feature owner CC-ed on this bug, please do your best to review these reports without the security team.
Overview: A parser differential in whitespace handling between the extension CSP validator and the network service allows a malicious extension to bypass sandbox restrictions. By using a form-feed character (\f), an extension can inject the allow-same-origin directive into a sandboxed page’s CSP, causing the page to commit with the extension’s privileged origin. In Manifest V3, this can lead to remote code execution within the extension context.
Affected files:
extensions/common/csp_validator.ccservices/network/public/cpp/web_sandbox_flags.cc
Estimated timestamp from git blame: 2018-10-23
Description
An extension’s sandbox Content Security Policy (CSP) must not include the allow-same-origin token. This ensures that sandboxed pages receive an opaque origin, preventing them from accessing privileged extension data or communicating with other extension contexts. This restriction is enforced in the ContentSecurityPolicyIsSandboxed function within extensions/common/csp_validator.cc.
There is a parser differential between the extension CSP validator and the browser’s network service CSP parser regarding the handling of the form-feed character (\f or \x0c).
- Extension Validator:
CSPParser::Parse(inextensions/common/csp_validator.cc:566) useskWhitespaceDelimiters(" \t\r\n") to tokenize the CSP. This list specifically excludes\f. - Network Service Parser:
ParseWebSandboxPolicy(inservices/network/public/cpp/web_sandbox_flags.cc:66) useskHtmlWhitespace(" \n\t\r\f"), which correctly includes the form-feed character per the HTML/CSP specifications.
By using a CSP directive such as sandbox allow-scripts allow-same-origin\fpadding, a malicious extension author can bypass the validator:
- The extension validator treats
allow-same-origin\fpaddingas a single token. Since this token does not exactly matchallow-same-origin, the validator accepts the CSP. - During navigation, the network service’s
ParseWebSandboxPolicysplits the directive on the\fcharacter, resulting in the tokensallow-same-originandpadding. Theallow-same-origintoken is recognized, and thekOriginflag is removed from the sandbox policy.
As a result, the sandboxed page commits with the extension’s privileged origin (chrome-extension://<id>) instead of the required opaque origin.
Impact
This is a bypass of origin-based isolation for sandboxed extension pages. In Manifest V3 (MV3), sandboxed pages are allowed to have a relaxed CSP that permits remote script execution. The security of this model relies entirely on the sandboxed page having an opaque origin to prevent it from interacting with the extension’s privileged components.
By gaining the extension’s origin, a remote script running in the sandboxed page can use IPC mechanisms that rely on the frame’s StorageKey (derived from the origin), such as BroadcastChannel or SharedWorker. This allows a remote script to communicate with the extension’s background page or other privileged contexts, effectively leading to remote code execution (RCE) in a context with access to chrome.* APIs, bypassing MV3 security restrictions.
Suggested Reproduction Steps
Note: These are potential steps as our tooling agent doesn’t yet have the ability to run code.
- Create a Manifest V3 extension with a manifest that defines a sandboxed page with a CSP containing a form-feed character:
(Ensure
{ "manifest_version": 3, "name": "CSP Bypass Test", "version": "1.0", "sandbox": { "pages": ["sandbox.html"] }, "content_security_policy": { "sandbox": "sandbox allow-scripts allow-same-origin\fpadding;" } }\fis the literal0x0Ccharacter) - Install the extension. The validator will fail to catch the
allow-same-origintoken due to the trailing form-feed and padding. - Navigate to the sandboxed page (
chrome-extension://<id>/sandbox.html). - Observe (e.g., via
window.origin) that the page has committed with thechrome-extension://<id>origin rather than an opaque origin. - Verify that the sandboxed page can now communicate with other extension pages via
BroadcastChannel.
Suggested Fix
Update kWhitespaceDelimiters in extensions/common/csp_validator.cc to include \f, or preferably, use base::kWhitespaceASCII to ensure consistency across the codebase.
Evaluated with Chrome root at commit: ff3d2b74fa39431785bd60e51463b08fcc71ee33
Results so far have been promising, but there can be wrong deductions. If this proves to be a false positive, please close as WAI; data from false positives will be used to improve accuracy over time. And please feel free to reach out to me directly if you have concerns or feedback on the project.