CVE-2026-18000
Overview
Background
- Guest context
- a
<webview>,<controlledframe>, orSlimWebViewembedded frame that runs in an isolated, non-defaultStoragePartitionfor content separation. - Device permission scope
- USB, Bluetooth, Serial, and File System Access grants are stored profile-wide, so any context sharing the profile inherits them regardless of its
StoragePartition. - `WebViewGuest::FromRenderFrameHost`
- the legacy, extension- and platform-specific check used to detect guest frames, compiled out when
ENABLE_EXTENSIONS_CORE/ENABLE_GUEST_VIEWare disabled (e.g. AndroidSlimWebView). - `GetSecurityPrincipal().IsGuest()`
- the platform-independent
content::SiteInstancepredicate that reports whether a frame is a guest without depending on the extensions build flags.
Root Cause Analysis
The device-permission delegates guarded guest access with extensions::WebViewGuest::FromRenderFrameHost(rfh), wrapped in #if BUILDFLAG(ENABLE_EXTENSIONS_CORE) && BUILDFLAG(ENABLE_GUEST_VIEW). On builds where those flags are off — notably Android SlimWebView — the entire guard was compiled out, so MayUseBluetooth and its USB/Serial/FSA siblings fell through to a weaker StoragePartition/URL-scheme fallback that could be bypassed by navigating to a non-http(s) scheme such as about:blank. Because device permissions are scoped profile-wide, a guest that slipped past the check would share the profile’s USB/Bluetooth/Serial/FSA grants, violating the isolation invariant that a non-default StoragePartition must not reach profile-level device permissions.
The fix replaces the extension-specific guard with rfh->GetSiteInstance()->GetSecurityPrincipal().IsGuest(), which identifies every guest context on every platform independent of build flags and returns denial before the fallback logic runs. The desktop <webview> File System Access compatibility exception is deliberately retained by keeping its prior conditional block ahead of the new IsGuest() check.
WebViewGuest), so the check vanished exactly where guests still existed (Android SlimWebView); the fix moves detection to the platform-independent GetSecurityPrincipal().IsGuest() so the guard is always compiled in and always fires.Attack Path
- Embed a guest
An attacker-influenced app or page instantiates a guest context (
<controlledframe>or AndroidSlimWebView) running in a non-defaultStoragePartitionunder the victim’s profile. - Evade the compiled-out check
On Android the
WebViewGuest::FromRenderFrameHostguard is compiled out, so no guest detection runs forMayUseBluetooth/USB/Serial/FSA. - Defeat the scheme fallback
The guest navigates to a non-http(s) URL such as
about:blankto slip past the URL-scheme-basedStoragePartitionfallback that would otherwise deny access. - Inherit profile grants Since device permissions are profile-scoped, the guest now reaches USB, Bluetooth, Serial, and File System Access grants belonging to the rest of the profile.
- Cross the isolation boundary The guest exercises those APIs against devices/files the embedder never authorized for that partition, completing the isolation bypass.
Impact Assessment
StoragePartition, breaking the intended device-permission isolation boundary. This is reachable from the browser process’s permission-delegate path and is most severe on Android, where the extensions check is absent and the about:blank scheme bypass applies. Preconditions are the ability to embed or drive a guest context (<webview>/<controlledframe>/SlimWebView) within a profile that already holds device/FSA grants.Changed Functions
| Function | Change | Notes |
|---|---|---|
source_setchrome/browser/bluetooth/BUILD.gn |
modified | |
ChromeBluetoothDelegateTestchrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc |
modified | |
TEST_Fchrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.cc |
modified |
Files Changed
chrome/browser/bluetooth/BUILD.gnchrome/browser/bluetooth/chrome_bluetooth_delegate.ccchrome/browser/bluetooth/chrome_bluetooth_delegate_unittest.ccchrome/browser/file_system_access/chrome_file_system_access_permission_context.ccchrome/browser/file_system_access/chrome_file_system_access_permission_context_unittest.cc
Audit Directions
- Build-flag-gated security checksSearch for isolation or permission guards wrapped in
#if BUILDFLAG(ENABLE_EXTENSIONS_CORE)/ENABLE_GUEST_VIEW; a guard that disappears on a build configuration where the threat still exists is a latent bypass. - Extension-specific guest detectionFlag uses of
WebViewGuest::FromRenderFrameHostor otherextensions::-namespaced guest tests in cross-platform delegates, and preferGetSecurityPrincipal().IsGuest()on theSiteInstance. - Profile-scoped grants in isolated partitionsAudit other profile-wide permission stores (device APIs, notifications, storage) reached from non-default
StoragePartitioncontexts, especially where URL-scheme fallbacks can be defeated byabout:blankor similar schemes.
Patch
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
Regression Test / PoC
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) {