Medium chrome Input Validation 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactImproper input validation in Permissions
DescriptionImproper input validation in Permissions
ComponentPermissions
Sub-componentPermissions
Bug ClassInput Validation
Tracker518099505
Fix commite54fa0cb3efa (chromium/src) +138/-6
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-20

Changed Functions

FunctionChangeNotes
if
chrome/browser/permissions/one_time_permissions_tracker_helper.cc
modified
EXPECT_TRUE
chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
modified

Files Changed

  • chrome/browser/permissions/one_time_permissions_tracker_helper.cc
  • chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
From e54fa0cb3efa6942800e6e6882bf6a75bd9041ef Mon Sep 17 00:00:00 2001
From: Antonio Sartori <antoniosartori@chromium.org>
Date: Wed, 16 Sep 2026 01:54:28 -0700
Subject: [PATCH] [permissions] Correctly track sandboxed origins for OTP expiration

This CL fixes the logic tracking one time permissions granted to
sandboxed opaque origins, making sure they expire as expected. Tests
are added to cover the expected behavior.

Bug: 518099505
Change-Id: I127f2257fd603c44cd84237d60ba5e9414d564ed
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8378781
Commit-Queue: Antonio Sartori <antoniosartori@chromium.org>
Reviewed-by: Thomas Nguyen <tungnh@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1698755}
---
diff --git a/chrome/browser/permissions/one_time_permissions_tracker_helper.cc b/chrome/browser/permissions/one_time_permissions_tracker_helper.cc
index ba98b8a..c7a1059 100644
--- a/chrome/browser/permissions/one_time_permissions_tracker_helper.cc
+++ b/chrome/browser/permissions/one_time_permissions_tracker_helper.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/permissions/one_time_permissions_condition_tracker.h"
 #include "chrome/browser/permissions/one_time_permissions_tracker.h"
 #include "chrome/browser/permissions/one_time_permissions_tracker_factory.h"
+#include "components/permissions/permission_util.h"
 #include "content/public/browser/page.h"
 #include "content/public/browser/page_user_data.h"
 #include "content/public/browser/visibility.h"
@@ -34,10 +35,16 @@
     : public content::PageUserData<OneTimePermissionsPageTracker> {
  public:
   static void MaybeCreateForPage(content::Page& page) {
-    if (ShouldIgnoreOrigin(page.GetMainDocument().GetLastCommittedOrigin())) {
+    // TODO(crbug.com/40226169): We should really use origins instead. Revisit
+    // this when we fix the GURL vs Origin problem in
+    // GetLastCommittedOriginAsURL.
+    url::Origin origin = url::Origin::Create(
+        permissions::PermissionUtil::GetLastCommittedOriginAsURL(
+            &page.GetMainDocument()));
+    if (ShouldIgnoreOrigin(origin)) {
       return;
     }
-    CreateForPage(page);
+    CreateForPage(page, origin);
   }
 
   ~OneTimePermissionsPageTracker() override;
@@ -47,7 +54,7 @@
   void OnIsCapturingAudioChanged(bool is_capturing_audio);
 
  private:
-  explicit OneTimePermissionsPageTracker(content::Page& page);
+  OneTimePermissionsPageTracker(content::Page& page, url::Origin origin);
 
   friend PageUserData;
   PAGE_USER_DATA_KEY_DECL();
@@ -66,9 +73,9 @@
 PAGE_USER_DATA_KEY_IMPL(OneTimePermissionsPageTracker);
 
 OneTimePermissionsPageTracker::OneTimePermissionsPageTracker(
-    content::Page& page)
-    : PageUserData(page),
-      origin_(page.GetMainDocument().GetLastCommittedOrigin()) {
+    content::Page& page,
+    url::Origin origin)
+    : PageUserData(page), origin_(std::move(origin)) {
   auto* tracker = OneTimePermissionsTrackerFactory::GetForBrowserContext(
       page.GetMainDocument().GetBrowserContext());
   if (!tracker) {
diff --git a/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc b/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
index 722f623..9703da4 100644
--- a/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
+++ b/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
@@ -33,9 +33,12 @@
 #include "chrome/test/base/test_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/content_settings_uma_util.h"
+#include "components/content_settings/core/browser/content_settings_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/browser/permission_settings_registry.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "components/content_settings/core/common/content_settings_types.mojom-shared.h"
 #include "components/content_settings/core/common/features.h"
 #include "components/performance_manager/public/performance_manager.h"
 #include "components/permissions/content_setting_permission_context_base.h"
@@ -47,6 +50,7 @@
 #include "components/permissions/permission_util.h"
 #include "components/permissions/permissions_client.h"
 #include "components/permissions/request_type.h"
+#include "components/permissions/resolvers/permission_prompt_options.h"
 #include "components/permissions/test/permission_request_observer.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/render_frame_host.h"
@@ -776,3 +780,124 @@
 
   hcsm->SetClockForTesting(base::DefaultClock::GetInstance());
 }
+
+IN_PROC_BROWSER_TEST_F(OneTimePermissionInteractiveUiTest,
+                       SandboxedOneTimeGrantRevokedOnTabClose) {
+  auto* hcsm =
+      HostContentSettingsMapFactory::GetForProfile(browser()->GetProfile());
+  GURL root_url = embedded_test_server()->GetURL("/");
+
+  const content_settings::PermissionSettingsInfo* permission_info =
+      content_settings::PermissionSettingsRegistry::GetInstance()->Get(
+          permissions::PermissionUtil::GetGeolocationType());
+  EXPECT_TRUE(
+      permission_info->delegate().IsUndecided(hcsm->GetPermissionSetting(
+          root_url, root_url,
+          permissions::PermissionUtil::GetGeolocationType())));
+
+  ASSERT_NO_FATAL_FAILURE(Initialize(
+      INITIALIZATION_DEFAULT,
+      embedded_test_server()->GetURL("/set-header-with-file/chrome/test/data/"
+                                     "geolocation/simple.html?Content-Security-"
+                                     "Policy: sandbox allow-scripts")));
+  EXPECT_TRUE(current_browser()
+                  ->tab_strip_model()
+                  ->GetActiveWebContents()
+                  ->GetPrimaryMainFrame()
+                  ->GetLastCommittedOrigin()
+                  .opaque());
+
+  WatchPositionAndExpectGrantedPermission(
+      permissions::PermissionRequestManager::ACCEPT_ONCE,
+      /*expect_prompt=*/true);
+
+  EXPECT_TRUE(permission_info->delegate().IsAnyPermissionAllowed(
+      hcsm->GetPermissionSetting(
+          root_url, root_url,
+          permissions::PermissionUtil::GetGeolocationType())));
+
+  ASSERT_NO_FATAL_FAILURE(
+      Initialize(INITIALIZATION_NEWTAB, GetDifferentOriginUrl()));
+
+  content::WebContentsDestroyedWatcher destroyed_watcher(
+      current_browser()->tab_strip_model()->GetWebContentsAt(0));
+  current_browser()->tab_strip_model()->CloseWebContentsAt(
+      0, TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
+  destroyed_watcher.Wait();
+
+  EXPECT_TRUE(base::test::RunUntil([&]() {
+    return permission_info->delegate().IsUndecided(hcsm->GetPermissionSetting(
+        root_url, root_url, permissions::PermissionUtil::GetGeolocationType()));
+  }));
+
+  OtpEventExpectBucketCount(
+      ContentSettingsType::GEOLOCATION,
+      permissions::OneTimePermissionEvent::ALL_TABS_CLOSED_OR_DISCARDED, 1);
+
+  ASSERT_NO_FATAL_FAILURE(
+      Initialize(INITIALIZATION_DEFAULT, GetGeolocationGurl()));
+  WatchPositionAndExpectGrantedPermission(
+      permissions::PermissionRequestManager::ACCEPT_ONCE,
+      /*expect_prompt=*/true);
+}
+
+IN_PROC_BROWSER_TEST_F(OneTimePermissionInteractiveUiTest,
+                       SandboxedOneTimeGrantRevokedInBackground) {
+  auto* hcsm =
+      HostContentSettingsMapFactory::GetForProfile(browser()->GetProfile());
+  GURL root_url = embedded_test_server()->GetURL("/");
+
+  const content_settings::PermissionSettingsInfo* permission_info =
+      content_settings::PermissionSettingsRegistry::GetInstance()->Get(
+          permissions::PermissionUtil::GetGeolocationType());
+  EXPECT_TRUE(
+      permission_info->delegate().IsUndecided(hcsm->GetPermissionSetting(
+          root_url, root_url,
+          permissions::PermissionUtil::GetGeolocationType())));
+
+  ASSERT_NO_FATAL_FAILURE(Initialize(
+      INITIALIZATION_DEFAULT,
+      embedded_test_server()->GetURL("/set-header-with-file/chrome/test/data/"
+                                     "geolocation/simple.html?Content-Security-"
+                                     "Policy: sandbox allow-scripts")));
+  EXPECT_TRUE(current_browser()
+                  ->tab_strip_model()
+                  ->GetActiveWebContents()
+                  ->GetPrimaryMainFrame()
+                  ->GetLastCommittedOrigin()
+                  .opaque());
+
+  WatchPositionAndExpectGrantedPermission(
+      permissions::PermissionRequestManager::ACCEPT_ONCE,
+      /*expect_prompt=*/true);
+
+  EXPECT_TRUE(permission_info->delegate().IsAnyPermissionAllowed(
+      hcsm->GetPermissionSetting(
+          root_url, root_url,
+          permissions::PermissionUtil::GetGeolocationType())));
+
+  ASSERT_NO_FATAL_FAILURE(
+      Initialize(INITIALIZATION_NEWTAB, GetDifferentOriginUrl()));
+
+  // Fast forward time to expire the permissions in the background.
+  task_runner_->FastForwardBy(permissions::kOneTimePermissionTimeout);
+
+  EXPECT_TRUE(base::test::RunUntil([&]() {
+    return permission_info->delegate().IsUndecided(hcsm->GetPermissionSetting(
+        root_url, root_url, permissions::PermissionUtil::GetGeolocationType()));
+  }));
+
+  current_browser()->tab_strip_model()->ActivateTabAt(0);
+
+  WatchPositionAndExpectGrantedPermission(
+      permissions::PermissionRequestManager::ACCEPT_ONCE,
+      /*expect_prompt=*/true);
+
+  OtpEventExpectBucketCount(
+      ContentSettingsType::GEOLOCATION,
+      permissions::OneTimePermissionEvent::GRANTED_ONE_TIME, 2);
+
+  OtpEventExpectBucketCount(
+      ContentSettingsType::GEOLOCATION,
+      permissions::OneTimePermissionEvent::EXPIRED_IN_BACKGROUND, 1);
+}
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc b/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
index 722f623..9703da4 100644
--- a/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
+++ b/chrome/browser/ui/views/permissions/one_time_permission_interactive_ui_test.cc
@@ -33,9 +33,12 @@
 #include "chrome/test/base/test_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/content_settings/core/browser/content_settings_uma_util.h"
+#include "components/content_settings/core/browser/content_settings_utils.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/content_settings/core/browser/permission_settings_registry.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/content_settings/core/common/content_settings_types.h"
+#include "components/content_settings/core/common/content_settings_types.mojom-shared.h"
 #include "components/content_settings/core/common/features.h"
 #include "components/performance_manager/public/performance_manager.h"
 #include "components/permissions/content_setting_permission_context_base.h"
@@ -47,6 +50,7 @@
 #include "components/permissions/permission_util.h"
 #include "components/permissions/permissions_client.h"
 #include "components/permissions/request_type.h"
+#include "components/permissions/resolvers/permission_prompt_options.h"
 #include "components/permissions/test/permission_request_observer.h"
 #include "components/strings/grit/components_strings.h"
 #include "content/public/browser/render_frame_host.h"
@@ -776,3 +780,124 @@
 
   hcsm->SetClockForTesting(base::DefaultClock::GetInstance());
 }
+
+IN_PROC_BROWSER_TEST_F(OneTimePermissionInteractiveUiTest,
+                       SandboxedOneTimeGrantRevokedOnTabClose) {
+  auto* hcsm =
+      HostContentSettingsMapFactory::GetForProfile(browser()->GetProfile());
+  GURL root_url = embedded_test_server()->GetURL("/");
+
+  const content_settings::PermissionSettingsInfo* permission_info =
+      content_settings::PermissionSettingsRegistry::GetInstance()->Get(
+          permissions::PermissionUtil::GetGeolocationType());
+  EXPECT_TRUE(
+      permission_info->delegate().IsUndecided(hcsm->GetPermissionSetting(
+          root_url, root_url,
+          permissions::PermissionUtil::GetGeolocationType())));
+
+  ASSERT_NO_FATAL_FAILURE(Initialize(
+      INITIALIZATION_DEFAULT,
+      embedded_test_server()->GetURL("/set-header-with-file/chrome/test/data/"
+                                     "geolocation/simple.html?Content-Security-"
+                                     "Policy: sandbox allow-scripts")));
+  EXPECT_TRUE(current_browser()
+                  ->tab_strip_model()
+                  ->GetActiveWebContents()
+                  ->GetPrimaryMainFrame()
+                  ->GetLastCommittedOrigin()
+                  .opaque());
+
+  WatchPositionAndExpectGrantedPermission(
+      permissions::PermissionRequestManager::ACCEPT_ONCE,
+      /*expect_prompt=*/true);
+
+  EXPECT_TRUE(permission_info->delegate().IsAnyPermissionAllowed(
+      hcsm->GetPermissionSetting(
+          root_url, root_url,
+          permissions::PermissionUtil::GetGeolocationType())));
+
+  ASSERT_NO_FATAL_FAILURE(
+      Initialize(INITIALIZATION_NEWTAB, GetDifferentOriginUrl()));
+
+  content::WebContentsDestroyedWatcher destroyed_watcher(
+      current_browser()->tab_strip_model()->GetWebContentsAt(0));
+  current_browser()->tab_strip_model()->CloseWebContentsAt(
+      0, TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
+  destroyed_watcher.Wait();
+
+  EXPECT_TRUE(base::test::RunUntil([&]() {
+    return permission_info->delegate().IsUndecided(hcsm->GetPermissionSetting(
+        root_url, root_url, permissions::PermissionUtil::GetGeolocationType()));
+  }));
+
+  OtpEventExpectBucketCount(
+      ContentSettingsType::GEOLOCATION,
+      permissions::OneTimePermissionEvent::ALL_TABS_CLOSED_OR_DISCARDED, 1);
+
+  ASSERT_NO_FATAL_FAILURE(
+      Initialize(INITIALIZATION_DEFAULT, GetGeolocationGurl()));
+  WatchPositionAndExpectGrantedPermission(
+      permissions::PermissionRequestManager::ACCEPT_ONCE,
+      /*expect_prompt=*/true);
+}
+
+IN_PROC_BROWSER_TEST_F(OneTimePermissionInteractiveUiTest,
+                       SandboxedOneTimeGrantRevokedInBackground) {
+  auto* hcsm =
+      HostContentSettingsMapFactory::GetForProfile(browser()->GetProfile());
+  GURL root_url = embedded_test_server()->GetURL("/");
+
+  const content_settings::PermissionSettingsInfo* permission_info =
+      content_settings::PermissionSettingsRegistry::GetInstance()->Get(
+          permissions::PermissionUtil::GetGeolocationType());
+  EXPECT_TRUE(
+      permission_info->delegate().IsUndecided(hcsm->GetPermissionSetting(
+          root_url, root_url,
+          permissions::PermissionUtil::GetGeolocationType())));
+
+  ASSERT_NO_FATAL_FAILURE(Initialize(
+      INITIALIZATION_DEFAULT,
+      embedded_test_server()->GetURL("/set-header-with-file/chrome/test/data/"
+                                     "geolocation/simple.html?Content-Security-"
+                                     "Policy: sandbox allow-scripts")));
+  EXPECT_TRUE(current_browser()
+                  ->tab_strip_model()
+                  ->GetActiveWebContents()
+                  ->GetPrimaryMainFrame()
+                  ->GetLastCommittedOrigin()
+                  .opaque());
+
+  WatchPositionAndExpectGrantedPermission(
+      permissions::PermissionRequestManager::ACCEPT_ONCE,
+      /*expect_prompt=*/true);
+
+  EXPECT_TRUE(permission_info->delegate().IsAnyPermissionAllowed(
+      hcsm->GetPermissionSetting(
+          root_url, root_url,
+          permissions::PermissionUtil::GetGeolocationType())));
+
+  ASSERT_NO_FATAL_FAILURE(
+      Initialize(INITIALIZATION_NEWTAB, GetDifferentOriginUrl()));
+
+  // Fast forward time to expire the permissions in the background.
+  task_runner_->FastForwardBy(permissions::kOneTimePermissionTimeout);
+
+  EXPECT_TRUE(base::test::RunUntil([&]() {
+    return permission_info->delegate().IsUndecided(hcsm->GetPermissionSetting(
+        root_url, root_url, permissions::PermissionUtil::GetGeolocationType()));
+  }));
+
+  current_browser()->tab_strip_model()->ActivateTabAt(0);
+
+  WatchPositionAndExpectGrantedPermission(
+      permissions::PermissionRequestManager::ACCEPT_ONCE,
+      /*expect_prompt=*/true);
+
+  OtpEventExpectBucketCount(
+      ContentSettingsType::GEOLOCATION,
+      permissions::OneTimePermissionEvent::GRANTED_ONE_TIME, 2);
+
+  OtpEventExpectBucketCount(
+      ContentSettingsType::GEOLOCATION,
+      permissions::OneTimePermissionEvent::EXPIRED_IN_BACKGROUND, 1);
+}
Loading diff…

Original Bug Report

reported by vm...@google.com

One-Time Permission Revocation Bypass on CSP-Sandboxed Pages via Opaque Origins

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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.

Overview: A logic discrepancy between the permission-granting code and the one-time permission tracker allows ‘Allow this time’ grants on top-level CSP-sandboxed pages to persist indefinitely. While the write path falls back to the visible URL (e.g., the root origin) to store the grant, the tracking/revocation path ignores the page due to its opaque origin. Consequently, the temporary permission remains active for up to 16 hours or until a non-sandboxed tab for the same origin is closed.

Affected files:

  • chrome/browser/permissions/one_time_permissions_tracker.cc
  • chrome/browser/permissions/one_time_permissions_tracker_helper.cc
  • components/permissions/permission_context_base.cc
  • components/permissions/permission_util.cc
  • chrome/browser/content_settings/one_time_permission_provider.cc

Estimated timestamp from git blame: 2024-08-13

Summary

A logic discrepancy between how permissions are granted (the “write path”) and how they are monitored and revoked (the “revocation path”) allows “Allow this time” (one-time) permission grants on top-level CSP-sandboxed pages to bypass cleanup. Consequently, rather than being revoked when the tab is closed, the grant persists for up to 16 hours or until a non-sandboxed tab of the same origin is opened and closed.

Potential Root Cause Analysis

1. The Write Path (Grant Storage)

When a permission is requested, PermissionContextBase derives the requesting and embedding origins. For embedding origins, it uses PermissionUtil::GetLastCommittedOriginAsURL on the RenderFrameHost:

GURL PermissionUtil::GetLastCommittedOriginAsURL(
    content::RenderFrameHost* render_frame_host) {
  ...
  GURL origin = render_frame_host->GetLastCommittedOrigin().GetURL();
  if (origin.is_empty() && render_frame_host->IsInPrimaryMainFrame()) {
    if (!web_contents->GetVisibleURL().is_empty()) {
      origin = web_contents->GetVisibleURL();
    }
  }
  return origin;
}

If a top-level page is loaded with a CSP sandbox header (e.g. Content-Security-Policy: sandbox allow-scripts), its last committed origin is opaque. Since url::Origin::GetURL() returns an empty GURL for opaque origins, the function falls back to web_contents->GetVisibleURL(). As a result, both requesting_origin and embedding_origin resolve to the visible URL (e.g., https://victim.com/). When the user chooses Allow this time, PermissionContextBase::UpdateSetting saves a SessionModel::ONE_TIME grant to the content settings database under this visible URL’s origin.

2. The Revocation Path (Tracker Logic)

OneTimePermissionsTrackerHelper and OneTimePermissionsTracker track tab loads, unloads, and backgrounding to perform cleanup. However, the helper tracks the real committed origin, which is opaque:

void OneTimePermissionsTrackerHelper::PrimaryPageChanged(content::Page& page) {
  url::Origin new_origin = page.GetMainDocument().GetLastCommittedOrigin();
  ...
  tracker->WebContentsLoadedOrigin(new_origin);
}

When this opaque origin is passed to the tracker, it checks ShouldIgnoreOrigin:

bool OneTimePermissionsTracker::ShouldIgnoreOrigin(const url::Origin& origin) {
  return origin.opaque() || ...;
}

Because the origin is opaque, ShouldIgnoreOrigin returns true, and the tracker ignores the page. It does not track its active tab count or initialize background-expiry timers. When the tab is closed, NotifyLastPageFromOriginClosed is never called for https://victim.com/, meaning the one-time permission grant remains active inside OneTimePermissionProvider.

3. Constraints & Edge Cases

The vulnerability is constrained by security CHECKs in PermissionContextBase::UpdateSetting:

CHECK_EQ(request_data.embedding_origin,
         request_data.embedding_origin.DeprecatedGetOriginAsURL());

Because DeprecatedGetOriginAsURL() strips the path, query, and fragment, any visible URL with a non-empty path (e.g., https://victim.com/sandbox.html) will trigger a browser process crash. Consequently, the persistence attack only succeeds if the sandboxed page is served directly from the origin-form root URL (e.g., https://victim.com/ with a trailing slash and no other path).


Potential Attack Scenario / Trigger Path

Note: These are suggested/potential steps, as our tooling cannot run arbitrary code to produce a live PoC.

  1. An attacker serves the root path of https://victim.com/ with the header Content-Security-Policy: sandbox allow-scripts and HTML that requests a delegated permission (e.g., Geolocation or Media).
  2. The user navigates to https://victim.com/ (a fresh tab/profile).
  3. The page requests the permission. The prompt is displayed to the user attributed to victim.com due to the visible URL fallback.
  4. The user selects Allow this time.
  5. The user closes the tab. Because the tracker ignored the opaque origin, the grant is not revoked.
  6. A subsequent navigation to https://victim.com/ (sandboxed or non-sandboxed) can silently consume the permission without any prompt.

Suggested Fix

Ensure that OneTimePermissionsTracker and OneTimePermissionsTrackerHelper are aligned with the origin resolution logic used when granting permissions, or ensure that opaque origins cannot obtain/retain permissions associated with their visible origin in a way that bypasses cleanup. One possible fix is to map opaque origins to their corresponding visible origin (if we are in the primary main frame) when performing tracker bookkeeping, or to reject permission requests from opaque origins entirely.

Evaluated with Chrome root at commit: fb72408a8493c46bc75fae1c70d03daec96b3040


Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:

  • If you are familiar with the severity guidelines, you may adjust the severity.
  • If this is a false positive, and there’s no work to be done, please close as WAI.
  • If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.

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