Medium chrome Logic Error 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInappropriate implementation in Extensions
DescriptionInappropriate implementation in Extensions
ComponentExtensions
Bug ClassLogic Error
Tracker498808432
Fix commitcd3b45a73d09 (chromium/src) +6/-3
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-02

Files Changed

  • extensions/common/csp_validator.cc
  • extensions/common/csp_validator_unittest.cc
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));
Loading diff…

Regression Test / PoC

shipped with the fix
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));
Loading diff…

Original Bug Report

reported by [email protected]

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.cc
  • services/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).

  1. Extension Validator: CSPParser::Parse (in extensions/common/csp_validator.cc:566) uses kWhitespaceDelimiters (" \t\r\n") to tokenize the CSP. This list specifically excludes \f.
  2. Network Service Parser: ParseWebSandboxPolicy (in services/network/public/cpp/web_sandbox_flags.cc:66) uses kHtmlWhitespace (" \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\fpadding as a single token. Since this token does not exactly match allow-same-origin, the validator accepts the CSP.
  • During navigation, the network service’s ParseWebSandboxPolicy splits the directive on the \f character, resulting in the tokens allow-same-origin and padding. The allow-same-origin token is recognized, and the kOrigin flag 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.

  1. Create a Manifest V3 extension with a manifest that defines a sandboxed page with a CSP containing a form-feed character:
    {
      "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;"
      }
    }
    
    (Ensure \f is the literal 0x0C character)
  2. Install the extension. The validator will fail to catch the allow-same-origin token due to the trailing form-feed and padding.
  3. Navigate to the sandboxed page (chrome-extension://<id>/sandbox.html).
  4. Observe (e.g., via window.origin) that the page has committed with the chrome-extension://<id> origin rather than an opaque origin.
  5. 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.

View on issue tracker