Low chrome Logic Error 🔧 Commit mapped

Overview

Low
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactInsufficient policy enforcement in USB
DescriptionInsufficient policy enforcement in USB
ComponentUSB
Bug ClassLogic Error
Tracker521623907
Fix commit4fe44fddb85c (chromium/src) +208/-37
CISA KEVNot listed
CreditedGoogle
Disclosed2026-07-29

Changed Functions

FunctionChangeNotes
source_set
chrome/browser/bluetooth/BUILD.gn
modified
ChromeBluetoothDelegateTest
chrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc
modified
TEST_F
chrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc
modified

Files Changed

  • chrome/browser/bluetooth/BUILD.gn
  • chrome/browser/bluetooth/chrome_bluetooth_delegate.cc
  • chrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc
  • chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
  • chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
From 4fe44fddb85c9d62ae179e0a580d238bdb27236d Mon Sep 17 00:00:00 2001
From: Rob Pitkin <[email protected]>
Date: Tue, 23 Jun 2026 14:38:30 -0700
Subject: [PATCH] permissions: Block guest contexts from device APIs

Because device permissions are scoped profile-wide, guest contexts (like
<webview>, <controlledframe>, and SlimWebView) that run in non-default
StoragePartitions would share device/FSA permissions with the rest of
the profile. This could lead to isolation bypasses, especially on
Android where the extensions system check is compiled out and fallback
logic based on URL schemes can be bypassed (e.g., by navigating to
about:blank).

This CL replaces the platform-conditional and extension-specific check
(WebViewGuest::FromRenderFrameHost) with the platform-independent
GetSiteInstance()->GetSecurityPrincipal().IsGuest() check. This ensures
that all guest contexts, including SlimWebView on Android, are properly
identified and blocked from accessing USB, Bluetooth, Serial, and File
System Access APIs. For File System Access on desktop, the legacy
<webview> compatibility exception is preserved by keeping the existing
conditional block.

Bug: 521623907
Change-Id: I5b2a1bcf359f3668949ee09485fbc47251a7c736
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7953106
Commit-Queue: Rob Pitkin <[email protected]>
Reviewed-by: Antonio Sartori <[email protected]>
Reviewed-by: Matt Reynolds <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1651293}
---

diff --git a/chrome/browser/bluetooth/BUILD.gn b/chrome/browser/bluetooth/BUILD.gn
index 49918f23..0ec41931 100644
--- a/chrome/browser/bluetooth/BUILD.gn
+++ b/chrome/browser/bluetooth/BUILD.gn
@@ -102,7 +102,10 @@
 
 source_set("unit_tests") {
   testonly = true
-  sources = [ "bluetooth_chooser_context_unittest.cc" ]
+  sources = [
+    "bluetooth_chooser_context_unittest.cc",
+    "chrome_bluetooth_delegate_unittest.cc",
+  ]
   deps = [
     ":bluetooth",
     "//chrome/browser/content_settings:content_settings_factory",
diff --git a/chrome/browser/bluetooth/chrome_bluetooth_delegate.cc b/chrome/browser/bluetooth/chrome_bluetooth_delegate.cc
index 8724f87..d13b97618 100644
--- a/chrome/browser/bluetooth/chrome_bluetooth_delegate.cc
+++ b/chrome/browser/bluetooth/chrome_bluetooth_delegate.cc
@@ -11,31 +11,25 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings_types.h"
-#include "components/guest_view/buildflags/buildflags.h"
 #include "components/permissions/bluetooth_delegate_impl.h"
 #include "components/permissions/content_setting_permission_context_base.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/render_frame_host.h"
-#include "extensions/buildflags/buildflags.h"
+#include "content/public/browser/security_principal.h"
+#include "content/public/browser/site_instance.h"
 #include "url/gurl.h"
 
-#if BUILDFLAG(ENABLE_EXTENSIONS_CORE) && BUILDFLAG(ENABLE_GUEST_VIEW)
-#include "extensions/browser/guest_view/web_view/web_view_guest.h"
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE) && BUILDFLAG(ENABLE_GUEST_VIEW)
-
 ChromeBluetoothDelegate::ChromeBluetoothDelegate(std::unique_ptr<Client> client)
     : permissions::BluetoothDelegateImpl(std::move(client)) {}
 
 bool ChromeBluetoothDelegate::MayUseBluetooth(content::RenderFrameHost* rfh) {
-#if BUILDFLAG(ENABLE_EXTENSIONS_CORE) && BUILDFLAG(ENABLE_GUEST_VIEW)
-  // Because permission is scoped to profile, <webview> and <controlledframe>,
-  // despite having isolated StoragePartition, will share bluetooth permission
-  // with the rest of the profile. Therefore bluetooth is not allowed in these
-  // contexts.
-  if (extensions::WebViewGuest::FromRenderFrameHost(rfh)) {
+  // Because permission is scoped to the profile, guest contexts (like
+  // <webview>, <controlledframe>, and SlimWebView), despite having isolated
+  // StoragePartitions, would share Bluetooth permissions with the rest of the
+  // profile. Therefore, Bluetooth is not allowed in these contexts.
+  if (rfh->GetSiteInstance()->GetSecurityPrincipal().IsGuest()) {
     return false;
   }
-#endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE) && BUILDFLAG(ENABLE_GUEST_VIEW)
 
   // Disable any other non-default StoragePartition contexts, unless it has a
   // non-http/https scheme.
diff --git a/chrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc b/chrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc
new file mode 100644
index 0000000..726601a
--- /dev/null
+++ b/chrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc
@@ -0,0 +1,70 @@
+// 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/bluetooth/chrome_bluetooth_delegate.h"
+
+#include <memory>
+
+#include "chrome/browser/bluetooth/chrome_bluetooth_delegate_impl_client.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/storage_partition_config.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/web_contents_tester.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+
+class ChromeBluetoothDelegateTest : public ChromeRenderViewHostTestHarness {
+ public:
+  std::unique_ptr<content::WebContents> CreateGuestWebContents(
+      const GURL& url) {
+    const content::StoragePartitionConfig kGuestConfig =
+        content::StoragePartitionConfig::Create(
+            profile(), "test_partition", "guest_partition", /*in_memory=*/true);
+    scoped_refptr<content::SiteInstance> guest_instance =
+        content::SiteInstance::CreateForGuest(profile(), kGuestConfig);
+    std::unique_ptr<content::WebContents> guest_contents =
+        content::WebContentsTester::CreateTestWebContents(profile(),
+                                                          guest_instance);
+    content::WebContentsTester::For(guest_contents.get())
+        ->NavigateAndCommit(url);
+    return guest_contents;
+  }
+};
+
+TEST_F(ChromeBluetoothDelegateTest, BlocksGuestViews) {
+  ChromeBluetoothDelegate bluetooth_delegate(
+      std::make_unique<ChromeBluetoothDelegateImplClient>());
+
+  // 1. Test HTTPS Guest (should be blocked)
+  {
+    std::unique_ptr<content::WebContents> guest =
+        CreateGuestWebContents(GURL("https://example.com/"));
+    EXPECT_FALSE(
+        bluetooth_delegate.MayUseBluetooth(guest->GetPrimaryMainFrame()));
+  }
+
+  // 2. Test about:blank Guest (should be blocked)
+  {
+    std::unique_ptr<content::WebContents> guest =
+        CreateGuestWebContents(GURL("about:blank"));
+    EXPECT_FALSE(
+        bluetooth_delegate.MayUseBluetooth(guest->GetPrimaryMainFrame()));
+  }
+
+  // 3. Test Non-Guest (should be allowed by default)
+  {
+    std::unique_ptr<content::WebContents> non_guest =
+        content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+    content::WebContentsTester::For(non_guest.get())
+        ->NavigateAndCommit(GURL("https://example.com/"));
+    EXPECT_TRUE(
+        bluetooth_delegate.MayUseBluetooth(non_guest->GetPrimaryMainFrame()));
+  }
+}
+
+}  // namespace
diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
index b544f92..a739d4b0 100644
--- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
+++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context.cc
@@ -65,6 +65,8 @@
 #include "content/public/browser/disallow_activation_reason.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/security_principal.h"
+#include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/buildflags/buildflags.h"
 #include "third_party/blink/public/common/features_generated.h"
@@ -2281,6 +2283,16 @@
   }
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE) && BUILDFLAG(ENABLE_GUEST_VIEW)
 
+  // Because permission is scoped to the profile, guest contexts (like
+  // <controlledframe> and SlimWebView), despite having isolated
+  // StoragePartitions, would share File System Access permissions with the rest
+  // of the profile. Therefore, we disable File System Access for guest
+  // contexts. Note that on desktop, <webview> is explicitly allowed to use FSA
+  // in the block above to avoid breaking existing usage.
+  if (rfh->GetSiteInstance()->GetSecurityPrincipal().IsGuest()) {
+    return base::unexpected(kDefaultNotAllowedMessage);
+  }
+
   // Disable any other non-default StoragePartition contexts. However, unique
   // schemes (e.g. isolated-app://) are exempt here.
   if (rfh->GetStoragePartition() !=
diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc b/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
index d6e6ae8..803f237 100644
--- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
+++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc b/chrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc
new file mode 100644
index 0000000..726601a
--- /dev/null
+++ b/chrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc
@@ -0,0 +1,70 @@
+// 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/bluetooth/chrome_bluetooth_delegate.h"
+
+#include <memory>
+
+#include "chrome/browser/bluetooth/chrome_bluetooth_delegate_impl_client.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/storage_partition_config.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/web_contents_tester.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+
+class ChromeBluetoothDelegateTest : public ChromeRenderViewHostTestHarness {
+ public:
+  std::unique_ptr<content::WebContents> CreateGuestWebContents(
+      const GURL& url) {
+    const content::StoragePartitionConfig kGuestConfig =
+        content::StoragePartitionConfig::Create(
+            profile(), "test_partition", "guest_partition", /*in_memory=*/true);
+    scoped_refptr<content::SiteInstance> guest_instance =
+        content::SiteInstance::CreateForGuest(profile(), kGuestConfig);
+    std::unique_ptr<content::WebContents> guest_contents =
+        content::WebContentsTester::CreateTestWebContents(profile(),
+                                                          guest_instance);
+    content::WebContentsTester::For(guest_contents.get())
+        ->NavigateAndCommit(url);
+    return guest_contents;
+  }
+};
+
+TEST_F(ChromeBluetoothDelegateTest, BlocksGuestViews) {
+  ChromeBluetoothDelegate bluetooth_delegate(
+      std::make_unique<ChromeBluetoothDelegateImplClient>());
+
+  // 1. Test HTTPS Guest (should be blocked)
+  {
+    std::unique_ptr<content::WebContents> guest =
+        CreateGuestWebContents(GURL("https://example.com/"));
+    EXPECT_FALSE(
+        bluetooth_delegate.MayUseBluetooth(guest->GetPrimaryMainFrame()));
+  }
+
+  // 2. Test about:blank Guest (should be blocked)
+  {
+    std::unique_ptr<content::WebContents> guest =
+        CreateGuestWebContents(GURL("about:blank"));
+    EXPECT_FALSE(
+        bluetooth_delegate.MayUseBluetooth(guest->GetPrimaryMainFrame()));
+  }
+
+  // 3. Test Non-Guest (should be allowed by default)
+  {
+    std::unique_ptr<content::WebContents> non_guest =
+        content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
+    content::WebContentsTester::For(non_guest.get())
+        ->NavigateAndCommit(GURL("https://example.com/"));
+    EXPECT_TRUE(
+        bluetooth_delegate.MayUseBluetooth(non_guest->GetPrimaryMainFrame()));
+  }
+}
+
+}  // namespace
diff --git a/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc b/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
index d6e6ae8..803f237 100644
--- a/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
+++ b/chrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
@@ -44,6 +44,8 @@
 #include "components/permissions/permission_util.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/browser/render_process_host.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/storage_partition_config.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_task_environment.h"
 #include "content/public/test/test_renderer_host.h"
@@ -513,6 +515,21 @@
     }));
   }
 
+  std::unique_ptr<content::WebContents> CreateGuestWebContents(
+      const GURL& url) {
+    const content::StoragePartitionConfig kGuestConfig =
+        content::StoragePartitionConfig::Create(
+            profile(), "test_partition", "guest_partition", /*in_memory=*/true);
+    scoped_refptr<content::SiteInstance> guest_instance =
+        content::SiteInstance::CreateForGuest(profile(), kGuestConfig);
+    std::unique_ptr<content::WebContents> guest_contents =
+        content::WebContentsTester::CreateTestWebContents(profile(),
+                                                          guest_instance);
+    content::WebContentsTester::For(guest_contents.get())
+        ->NavigateAndCommit(url);
+    return guest_contents;
+  }
+
   content::BrowserTaskEnvironment task_environment_{
       base::test::TaskEnvironment::TimeSource::MOCK_TIME};
   base::ScopedTempDir temp_dir_;
@@ -549,6 +566,27 @@
 };
 
 TEST_F(ChromeFileSystemAccessPermissionContextTest,
+       CanShowFilePicker_BlocksGuestViews) {
+  // 1. Test HTTPS Guest (should be blocked)
+  {
+    std::unique_ptr<content::WebContents> guest =
+        CreateGuestWebContents(GURL("https://example.com/"));
+    EXPECT_FALSE(permission_context()
+                     ->CanShowFilePicker(guest->GetPrimaryMainFrame())
+                     .has_value());
+  }
+
+  // 2. Test about:blank Guest (should be blocked)
+  {
+    std::unique_ptr<content::WebContents> guest =
+        CreateGuestWebContents(GURL("about:blank"));
+    EXPECT_FALSE(permission_context()
+                     ->CanShowFilePicker(guest->GetPrimaryMainFrame())
+                     .has_value());
+  }
+}
+
+TEST_F(ChromeFileSystemAccessPermissionContextTest,
        ConfirmSensitiveEntryAccess_NoSpecialPath) {
   const PathInfo kTestPathInfo(FILE_PATH_LITERAL(
 #if defined(FILE_PATH_USES_DRIVE_LETTERS)
diff --git a/chrome/browser/serial/chrome_serial_delegate_unittest.cc b/chrome/browser/serial/chrome_serial_delegate_unittest.cc
index d933772..b499836 100644
--- a/chrome/browser/serial/chrome_serial_delegate_unittest.cc
+++ b/chrome/browser/serial/chrome_serial_delegate_unittest.cc
@@ -80,4 +80,26 @@
          "non-default-partition frames";
 }
 
+TEST_F(ChromeSerialDelegateStoragePartitionTest, SerialBlocksGuestViews) {
+  ChromeSerialDelegate serial_delegate;
+
+  // 1. Test HTTPS Guest (should be blocked)
+  {
+    const GURL kGuestUrl("https://example.com/");
+    std::unique_ptr<content::WebContents> guest =
+        CreateGuestPartitionWebContents(kGuestUrl);
+    content::RenderFrameHost* rfh = guest->GetPrimaryMainFrame();
+    EXPECT_FALSE(serial_delegate.CanRequestPortPermission(rfh));
+  }
+
+  // 2. Test about:blank Guest (should be blocked)
+  {
+    const GURL kGuestUrl("about:blank");
+    std::unique_ptr<content::WebContents> guest =
+        CreateGuestPartitionWebContents(kGuestUrl);
+    content::RenderFrameHost* rfh = guest->GetPrimaryMainFrame();
+    EXPECT_FALSE(serial_delegate.CanRequestPortPermission(rfh));
+  }
+}
+
 }  // namespace
diff --git a/chrome/browser/usb/chrome_usb_delegate_unittest.cc b/chrome/browser/usb/chrome_usb_delegate_unittest.cc
index c008fa9..9463c12 100644
--- a/chrome/browser/usb/chrome_usb_delegate_unittest.cc
+++ b/chrome/browser/usb/chrome_usb_delegate_unittest.cc
@@ -18,9 +18,11 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "content/public/browser/site_instance.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/embedded_worker_instance_test_harness.h"
 #include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
 #include "services/device/public/cpp/test/fake_usb_device_info.h"
 #include "services/device/public/cpp/test/fake_usb_device_manager.h"
 #include "services/device/public/cpp/test/scoped_usb_device_manager_overrider.h"
@@ -918,6 +920,42 @@
 
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS_CORE)
 
+class ChromeUsbDelegateGuestTest : public ChromeRenderViewHostTestHarness {
+ public:
+  std::unique_ptr<content::WebContents> CreateGuestWebContents(
+      const GURL& url) {
+    const content::StoragePartitionConfig kGuestConfig =
+        content::StoragePartitionConfig::Create(
+            profile(), "test_partition", "guest_partition", /*in_memory=*/true);
+    scoped_refptr<content::SiteInstance> guest_instance =
+        content::SiteInstance::CreateForGuest(profile(), kGuestConfig);
+    std::unique_ptr<content::WebContents> guest_contents =
+        content::WebContentsTester::CreateTestWebContents(profile(),
+                                                          guest_instance);
+    content::WebContentsTester::For(guest_contents.get())
+        ->NavigateAndCommit(url);
+    return guest_contents;
+  }
+};
+
+TEST_F(ChromeUsbDelegateGuestTest, BlocksGuestViews) {
+  ChromeUsbDelegate usb_delegate;
+
+  // 1. Test HTTPS Guest
+  {
+    std::unique_ptr<content::WebContents> guest =
+        CreateGuestWebContents(GURL("https://example.com/"));
+    EXPECT_FALSE(usb_delegate.PageMayUseUsb(guest->GetPrimaryPage()));
+  }
+
+  // 2. Test about:blank Guest
+  {
+    std::unique_ptr<content::WebContents> guest =
+        CreateGuestWebContents(GURL("about:blank"));
+    EXPECT_FALSE(usb_delegate.PageMayUseUsb(guest->GetPrimaryPage()));
+  }
+}
+
 }  // namespace
 
 TEST_F(ChromeUsbDelegateRenderFrameTest, NoPermissionDevice) {
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.