CVE-2026-95355
Overview
Background
- `CRWWKNavigationHandler`
- the iOS
//ios/webclass that implements theWKNavigationDelegateprotocol and decides, per navigation, whetherWKWebViewmay proceed. - Error page file URL
- a local
file://URL (identified by[CRWErrorPageHelper isErrorPageFileURL:]) that renders Chrome’s committed error page for a failed navigation. - `WKNavigationTypeBackForward` / `WKNavigationTypeReload`
WebKitnavigation-type flags marking a navigation as a history traversal or reload of an already-committed item rather than a fresh, script-initiable load.- `native_restore_in_progress_`
- the
NavigationManagerImplflag, exposed by the newIsRestoreSessionInProgress(), that is set only while the system is restoring a saved session.
Root Cause Analysis
In -[CRWWKNavigationHandler webView:decidePolicyForNavigationAction:decisionHandler:], any navigation whose target URL satisfied [CRWErrorPageHelper isErrorPageFileURL:requestURL] was unconditionally allowed with WKNavigationActionPolicyAllow, with no check on who initiated it. Because the local error page is a real file:// document that Chrome grants read access to, a renderer- or page-initiated navigation to such a URL was treated as trusted, violating the invariant that error page file URLs may only be loaded under browser control.
The fix records the exact URL the browser intends to load in a new allowedErrorPageFileURL property and only permits an error page navigation when it matches that expected URL in the main frame, or when it is a genuine WKNavigationTypeBackForward / WKNavigationTypeReload of a committed page, or while IsRestoreSessionInProgress() is true; everything else is now WKNavigationActionPolicyCancel. It additionally tightens the outbound path so navigations originating from an error page are only allowed back to the failed URL that error page represents. Together these gates ensure error page file URLs are loaded only in contexts the browser explicitly authorized.
Attack Path
- Reach the unguarded allow branch
A page or renderer-controlled navigation targets a URL that
[CRWErrorPageHelper isErrorPageFileURL:]recognizes, hitting the branch that previously returnedWKNavigationActionPolicyAllowunconditionally. - Load the local error page file URL
Because no initiator or expected-URL check existed,
WKWebViewcommits the localfile://error page document even though the browser never requested that specific load. - Abuse the error page's privileged position (inferred)
A committed error page document has an outbound allowance for onward navigation (the
isErrorPageFileURL:self.documentURLpath), which an attacker-controlled error page context could try to leverage toward otherwise-restricted URLs; the fix now constrains this to only the failed URL the error page represents. - Escalate to an authorization bypass in navigation (inferred)
The net effect the advisory describes is incorrect authorization in
Navigation, i.e. performing a navigation state or context the origin should not be able to reach; the precise downstream primitive is not shown by the diff.
Impact Assessment
Navigation (bug 508462481). The preconditions are that the attacker controls or influences a navigation and that it is neither a legitimate back/forward, reload, nor session restore; further escalation beyond loading the error page document is (inferred) and not directly demonstrated by the patch. The vendor advisory rates this high severity and does not report in-the-wild exploitation; NVD scores it CVSS 8.3.Changed Functions
| Function | Change | Notes |
|---|---|---|
ifios/web/navigation/crw_wk_navigation_handler.mm |
modified | |
ifios/web/navigation/navigation_manager_impl.mm |
modified | |
TEST_Fios/web/web_state/ui/crw_web_controller_unittest.mm |
modified | |
WindowOpenByDomTestios/web/web_state/ui/crw_web_controller_unittest.mm |
modified |
Files Changed
ios/web/navigation/navigation_manager_impl.mmios/web/web_state/ui/crw_web_controller_unittest.mmios/web/navigation/navigation_manager_impl.hios/web/navigation/crw_wk_navigation_handler.mm
Audit Directions
- URL-shape authorizationAudit navigation delegates that grant
Allowbased on a destination URL predicate (scheme,file://error/WebUI paths) rather than the navigation’s initiator or type, especially unconditional early-return allow branches. - Dangling trust stateReview one-shot “expected URL” or capability tokens like
allowedErrorPageFileURLto confirm they are cleared on every path (main-frame navigations, HTML-string loads) so a stale value cannot authorize a later unrelated load. - Error/interstitial page privilegeInspect what committed error, interstitial, or WebUI documents are permitted to navigate to, ensuring onward navigations are constrained to the specific failed URL they represent rather than a broad category.
Patch
From bb617c8b09d43ed4d617d0c2b6769899324c9ee8 Mon Sep 17 00:00:00 2001 From: Justin Cohen <[email protected]> Date: Fri, 21 Aug 2026 12:07:28 -0700 Subject: [PATCH] ios: Validate error page navigations in CRWWKNavigationHandler. Error page navigations inside CRWWKNavigationHandler can currently be initiated by any context. This change ensures that navigations to local error page file URLs are only allowed if explicitly initiated by the browser process, or if they are safe back/forward or reload navigations of already committed pages. It also allows error page loads during active session restoration, which is securely managed by the system. Bug: 508462481 Change-Id: Ic17c3eaa553b80ca5a62de4ab0178be38a5de8b4 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7862880 Auto-Submit: Justin Cohen <[email protected]> Reviewed-by: Matt Reichhoff <[email protected]> Reviewed-by: Mike Dougherty <[email protected]> Commit-Queue: Mike Dougherty <[email protected]> Cr-Commit-Position: refs/heads/main@{#1684115} --- diff --git a/ios/web/navigation/crw_wk_navigation_handler.mm b/ios/web/navigation/crw_wk_navigation_handler.mm index 2956871..716679ef 100644 --- a/ios/web/navigation/crw_wk_navigation_handler.mm +++ b/ios/web/navigation/crw_wk_navigation_handler.mm @@ -179,6 +179,7 @@ } @property(nonatomic, weak) id<CRWWKNavigationHandlerDelegate> delegate; +@property(nonatomic, copy) NSURL* allowedErrorPageFileURL; // Returns the WebStateImpl from self.delegate. @property(nonatomic, readonly, assign) web::WebStateImpl* webStateImpl; @@ -331,9 +332,31 @@ } } - // If this is a error navigation, pass through. + // Error pages must only be loaded in the main frame. Unconditionally clear + // the allowed error page URL on any main frame navigation to prevent dangling + // states (e.g., if a load HTML string request was made instead of a + // file URL load). + NSURL* allowedErrorPageFileURL = self.allowedErrorPageFileURL; + if (action.targetFrame.mainFrame) { + self.allowedErrorPageFileURL = nil; + } + + // If this is an error navigation, pass through only if initiated by the + // browser, or if it is a back/forward or reload of an already committed page. if ([CRWErrorPageHelper isErrorPageFileURL:requestURL]) { - decisionHandler(WKNavigationActionPolicyAllow); + BOOL isHistoryOrReloadOrRestore = + action.navigationType == WKNavigationTypeBackForward || + action.navigationType == WKNavigationTypeReload || + self.navigationManagerImpl->IsRestoreSessionInProgress(); + BOOL isExpectedErrorPage = + allowedErrorPageFileURL && + requestURL == net::GURLWithNSURL(allowedErrorPageFileURL); + if ((isExpectedErrorPage && action.targetFrame.mainFrame) || + isHistoryOrReloadOrRestore) { + decisionHandler(WKNavigationActionPolicyAllow); + return; + } + decisionHandler(WKNavigationActionPolicyCancel); return; } @@ -1483,9 +1506,12 @@ } } - // Allow navigation to WebUI pages from error pages. + // Allow navigation from an error page to the failed URL it represents so + // that error pages for app-specific URLs can retry the original navigation. if ([CRWErrorPageHelper isErrorPageFileURL:self.documentURL]) { - return YES; + return requestURL == + [CRWErrorPageHelper + failedNavigationURLFromErrorPageFileURL:self.documentURL]; } if (!action.sourceFrame.mainFrame) { @@ -2144,6 +2170,7 @@ isErrorPageFileURLForFailedNavigationURL:backForwardItem.URL] && !isSameURLFromWebClient && ![backForwardItem.URL isEqual:errorPage.failedNavigationURL]) { + self.allowedErrorPageFileURL = errorPage.errorPageFileURL; errorNavigation = [webView loadFileURL:errorPage.errorPageFileURL allowingReadAccessToURL:errorPage.errorPageFileURL]; } else { diff --git a/ios/web/navigation/navigation_manager_impl.h b/ios/web/navigation/navigation_manager_impl.h index d71cde27..0951dbe 100644 --- a/ios/web/navigation/navigation_manager_impl.h +++ b/ios/web/navigation/navigation_manager_impl.h @@ -208,6 +208,7 @@ // TODO(crbug.com/41284081): Make this private once all navigation code is // moved out of CRWWebController. NavigationItemImpl* GetCurrentItemImpl() const; + bool IsRestoreSessionInProgress() const; // Implementation for corresponding NavigationManager getters. NavigationItemImpl* GetPendingItemImpl() const; diff --git a/ios/web/navigation/navigation_manager_impl.mm b/ios/web/navigation/navigation_manager_impl.mm index 1aa8b484..4719013 100644 --- a/ios/web/navigation/navigation_manager_impl.mm +++ b/ios/web/navigation/navigation_manager_impl.mm @@ -847,6 +847,10 @@ return GetLastCommittedItemImpl(); } +bool NavigationManagerImpl::IsRestoreSessionInProgress() const { + return native_restore_in_progress_; +} + NavigationItemImpl* NavigationManagerImpl::GetLastCommittedItemImpl() const { if (empty_window_open_item_) { return empty_window_open_item_.get(); diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index 0cc4a777..34f234f 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm @@ -9,6 +9,7 @@ #import <memory> #import <utility> +#import "base/apple/bundle_locations.h" #import "base/apple/foundation_util.h" #import "base/scoped_observation.h" #import "base/strings/sys_string_conversions.h" @@ -22,6 +23,7 @@ #import "ios/web/common/uikit_ui_util.h" #import "ios/web/js_messaging/web_view_js_utils.h" #import "ios/web/navigation/block_universal_links_buildflags.h" +#import "ios/web/navigation/crw_wk_navigation_handler.h" #import "ios/web/navigation/crw_wk_navigation_states.h" #import "ios/web/navigation/navigation_item_impl.h" #import "ios/web/navigation/navigation_manager_impl.h" @@ -62,6 +64,27 @@ #import "third_party/ocmock/ocmock_extensions.h" #import "url/scheme_host_port.h" +@interface CRWWebController (Testing) +@property(nonatomic, readonly) CRWWKNavigationHandler* navigationHandler; +@end + +@interface CRWWKNavigationHandler (Testing) +@property(nonatomic, copy) NSURL* allowedErrorPageFileURL; +@end +@interface FakeWKFrameInfo : NSObject <NSCopying> +@property(nonatomic, assign, getter=isMainFrame) BOOL mainFrame; +@end + +@implementation FakeWKFrameInfo +@synthesize mainFrame = _mainFrame; + +- (id)copyWithZone:(NSZone*)zone { + FakeWKFrameInfo* copy = [[[self class] allocWithZone:zone] init]; + copy.mainFrame = self.mainFrame; + return copy; +} +@end + using base::test::ios::kWaitForJSCompletionTimeout; using base::test::ios::kWaitForPageLoadTimeout; using base::test::ios::WaitUntilConditionOrTimeout; @@ -1248,6 +1271,85 @@ url_request, WKNavigationActionPolicyCancel)); } +// Tests that a forged navigation to an error page URL is blocked/cancelled +// when the browser didn't initiate it, and successfully allowed when the +// browser did, but restricted strictly to main frame navigations and cleared. +TEST_F(CRWWebControllerPolicyDeciderTest, RejectForgedErrorPageNavigation) { + NSString* path = + [base::apple::FrameworkBundle() pathForResource:@"error_page_loaded" + ofType:@"html"]; + ASSERT_TRUE(path); + NSURL* forged_error_url = [NSURL + URLWithString:[NSString + stringWithFormat:@"file://%@?url=chrome://settings", + path]]; + NSMutableURLRequest* forged_request = + [NSMutableURLRequest requestWithURL:forged_error_url]; + forged_request.mainDocumentURL = forged_error_url; + + // Use FakeWKFrameInfo to avoid OCMock copying and swizzling issues. + FakeWKFrameInfo* fake_frame = [[FakeWKFrameInfo alloc] init]; + + CRWFakeWKNavigationAction* action = [[CRWFakeWKNavigationAction alloc] init]; + action.request = forged_request; + + // Default case: error page load is blocked when not initiated by browser. + fake_frame.mainFrame = YES; + action.targetFrame = (WKFrameInfo*)fake_frame; + __block bool callback_called = false; + [navigation_delegate_ webView:mock_web_view_ + decidePolicyForNavigationAction:action + preferences:[[WKWebpagePreferences alloc] init] + decisionHandler:^(WKNavigationActionPolicy policy, + WKWebpagePreferences* ignored) { + EXPECT_EQ(policy, WKNavigationActionPolicyCancel); + callback_called = true; + }]; + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ + return callback_called; + })); + + [web_controller() navigationHandler].allowedErrorPageFileURL = + forged_error_url; + + // Subframe error page load is blocked and does not clear the flag. + fake_frame.mainFrame = NO; + action.targetFrame = (WKFrameInfo*)fake_frame; + callback_called = false; + [navigation_delegate_ webView:mock_web_view_ + decidePolicyForNavigationAction:action + preferences:[[WKWebpagePreferences alloc] init] + decisionHandler:^(WKNavigationActionPolicy policy, + WKWebpagePreferences* ignored) { + EXPECT_EQ(policy, WKNavigationActionPolicyCancel); + callback_called = true; + }]; + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ + return callback_called; + })); + + EXPECT_TRUE([[web_controller() navigationHandler].allowedErrorPageFileURL + isEqual:forged_error_url]); + + // Main frame navigation is allowed and clears the flag. + fake_frame.mainFrame = YES; + action.targetFrame = (WKFrameInfo*)fake_frame; + callback_called = false; + [navigation_delegate_ webView:mock_web_view_ + decidePolicyForNavigationAction:action + preferences:[[WKWebpagePreferences alloc] init] + decisionHandler:^(WKNavigationActionPolicy policy, + WKWebpagePreferences* ignored) { + EXPECT_EQ(policy, WKNavigationActionPolicyAllow); + callback_called = true; + }]; + EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{ + return callback_called; + })); + + EXPECT_FALSE([web_controller() navigationHandler].allowedErrorPageFileURL); +} + // Test fixture for window.open tests. class WindowOpenByDomTest : public WebTestWithWebController { protected:
Regression Test / PoC
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index 0cc4a777..34f234f 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -9,6 +9,7 @@
#import <memory>
#import <utility>
+#import "base/apple/bundle_locations.h"
#import "base/apple/foundation_util.h"
#import "base/scoped_observation.h"
#import "base/strings/sys_string_conversions.h"
@@ -22,6 +23,7 @@
#import "ios/web/common/uikit_ui_util.h"
#import "ios/web/js_messaging/web_view_js_utils.h"
#import "ios/web/navigation/block_universal_links_buildflags.h"
+#import "ios/web/navigation/crw_wk_navigation_handler.h"
#import "ios/web/navigation/crw_wk_navigation_states.h"
#import "ios/web/navigation/navigation_item_impl.h"
#import "ios/web/navigation/navigation_manager_impl.h"
@@ -62,6 +64,27 @@
#import "third_party/ocmock/ocmock_extensions.h"
#import "url/scheme_host_port.h"
+@interface CRWWebController (Testing)
+@property(nonatomic, readonly) CRWWKNavigationHandler* navigationHandler;
+@end
+
+@interface CRWWKNavigationHandler (Testing)
+@property(nonatomic, copy) NSURL* allowedErrorPageFileURL;
+@end
+@interface FakeWKFrameInfo : NSObject <NSCopying>
+@property(nonatomic, assign, getter=isMainFrame) BOOL mainFrame;
+@end
+
+@implementation FakeWKFrameInfo
+@synthesize mainFrame = _mainFrame;
+
+- (id)copyWithZone:(NSZone*)zone {
+ FakeWKFrameInfo* copy = [[[self class] allocWithZone:zone] init];
+ copy.mainFrame = self.mainFrame;
+ return copy;
+}
+@end
+
using base::test::ios::kWaitForJSCompletionTimeout;
using base::test::ios::kWaitForPageLoadTimeout;
using base::test::ios::WaitUntilConditionOrTimeout;
@@ -1248,6 +1271,85 @@
url_request, WKNavigationActionPolicyCancel));
}
+// Tests that a forged navigation to an error page URL is blocked/cancelled
+// when the browser didn't initiate it, and successfully allowed when the
+// browser did, but restricted strictly to main frame navigations and cleared.
+TEST_F(CRWWebControllerPolicyDeciderTest, RejectForgedErrorPageNavigation) {
+ NSString* path =
+ [base::apple::FrameworkBundle() pathForResource:@"error_page_loaded"
+ ofType:@"html"];
+ ASSERT_TRUE(path);
+ NSURL* forged_error_url = [NSURL
+ URLWithString:[NSString
+ stringWithFormat:@"file://%@?url=chrome://settings",
+ path]];
+ NSMutableURLRequest* forged_request =
+ [NSMutableURLRequest requestWithURL:forged_error_url];
+ forged_request.mainDocumentURL = forged_error_url;
+
+ // Use FakeWKFrameInfo to avoid OCMock copying and swizzling issues.
+ FakeWKFrameInfo* fake_frame = [[FakeWKFrameInfo alloc] init];
+
+ CRWFakeWKNavigationAction* action = [[CRWFakeWKNavigationAction alloc] init];
+ action.request = forged_request;
+
+ // Default case: error page load is blocked when not initiated by browser.
+ fake_frame.mainFrame = YES;
+ action.targetFrame = (WKFrameInfo*)fake_frame;
+ __block bool callback_called = false;
+ [navigation_delegate_ webView:mock_web_view_
+ decidePolicyForNavigationAction:action
+ preferences:[[WKWebpagePreferences alloc] init]
+ decisionHandler:^(WKNavigationActionPolicy policy,
+ WKWebpagePreferences* ignored) {
+ EXPECT_EQ(policy, WKNavigationActionPolicyCancel);
+ callback_called = true;
+ }];
+ EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
+ return callback_called;
+ }));
+
+ [web_controller() navigationHandler].allowedErrorPageFileURL =
+ forged_error_url;
+
+ // Subframe error page load is blocked and does not clear the flag.
+ fake_frame.mainFrame = NO;
+ action.targetFrame = (WKFrameInfo*)fake_frame;
+ callback_called = false;
+ [navigation_delegate_ webView:mock_web_view_
+ decidePolicyForNavigationAction:action
+ preferences:[[WKWebpagePreferences alloc] init]
+ decisionHandler:^(WKNavigationActionPolicy policy,
+ WKWebpagePreferences* ignored) {
+ EXPECT_EQ(policy, WKNavigationActionPolicyCancel);
+ callback_called = true;
+ }];
+ EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
+ return callback_called;
+ }));
+
+ EXPECT_TRUE([[web_controller() navigationHandler].allowedErrorPageFileURL
+ isEqual:forged_error_url]);
+
+ // Main frame navigation is allowed and clears the flag.
+ fake_frame.mainFrame = YES;
+ action.targetFrame = (WKFrameInfo*)fake_frame;
+ callback_called = false;
+ [navigation_delegate_ webView:mock_web_view_
+ decidePolicyForNavigationAction:action
+ preferences:[[WKWebpagePreferences alloc] init]
+ decisionHandler:^(WKNavigationActionPolicy policy,
+ WKWebpagePreferences* ignored) {
+ EXPECT_EQ(policy, WKNavigationActionPolicyAllow);
+ callback_called = true;
+ }];
+ EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForPageLoadTimeout, ^{
+ return callback_called;
+ }));
+
+ EXPECT_FALSE([web_controller() navigationHandler].allowedErrorPageFileURL);
+}
+
// Test fixture for window.open tests.
class WindowOpenByDomTest : public WebTestWithWebController {
protected:
Original Bug Report
Potential WebUI Privilege Escalation via Forged Error Page Navigation in iOS
Flapjack, 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 Chrome Security team. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A compromised renderer process on iOS can potentially escalate its privileges to a WebUI context. It achieves this by forging a navigation to a local error page file, which bypasses validation and subsequently authorizes a redirect to a privileged chrome:// URL.
Affected files:
ios/web/navigation/crw_wk_navigation_handler.mmios/web/navigation/crw_error_page_helper.mm
Estimated timestamp from git blame: 2025-06-25
Description
A potential Confused Deputy vulnerability exists in the iOS Chromium navigation handler (crw_wk_navigation_handler.mm). It may allow a compromised renderer process (Renderer RCE) to bypass navigation restrictions and force the browser to load and grant privileges to App-Specific URLs (e.g., chrome:// WebUI pages).
The Flaw
The vulnerability stems from insufficient validation of navigations to internal error pages. In ios/web/navigation/crw_wk_navigation_handler.mm, the webView:decidePolicyForNavigationAction:preferences:decisionHandler: method unconditionally allows a navigation if the destination URL is identified as an internal error page:
// If this is a error navigation, pass through.
if ([CRWErrorPageHelper isErrorPageFileURL:requestURL]) {
decisionHandler(WKNavigationActionPolicyAllow);
return;
}
The helper method isErrorPageFileURL: (in ios/web/navigation/crw_error_page_helper.mm) only verifies that the URL scheme is file://, the path matches the expected app bundle path for error_page_loaded.html, and it contains a valid url parameter. It lacks an unforgeable token or state verification to distinguish between a legitimate browser-initiated error page load and a malicious renderer-initiated load.
Potential Exploitation Chain
(Note: These are potential steps based on code analysis; a functional exploit has not been executed).
- Renderer Compromise: An attacker achieves Remote Code Execution (RCE) in the sandboxed renderer process (
WebContenton iOS). - Path Discovery: The compromised renderer identifies its own iOS app bundle path to construct the exact local file path to
error_page_loaded.html. - Forged Navigation: The attacker executes JavaScript in the compromised renderer to initiate a main-frame navigation to the local error page file, bypassing standard web restrictions by appending a target URL:
window.location.href = "file://[bundle_path]/error_page_loaded.html?url=chrome://settings". - Policy Bypass: The Browser process receives this request in
decidePolicyForNavigationAction:. TheisErrorPageFileURL:check returnsYES, and the navigation is allowed early, bypassing further security checks. - State Corruption: When the navigation commits, the Browser process updates its internal tracking of the current page URL (
self.documentURL) to this malicious file URL. - Error Page Execution: The legitimate
error_page_loaded.htmlfile loads in the renderer. Its embedded JavaScript automatically executeswindow.location.replace(failedUrl), wherefailedUrlis thechrome://settingsparameter. - WebUI Escalation: The renderer initiates a second navigation to
chrome://settings. The Browser process evaluates this usingshouldAllowAppSpecificURLNavigationAction:. Because the currentdocumentURLis now an error page, the following check passes:
// Allow navigation to WebUI pages from error pages.
if ([CRWErrorPageHelper isErrorPageFileURL:self.documentURL]) {
return YES;
}
- Sandbox Escape: The Browser process allows the navigation and proceeds to call
createWebUIForURL:, which provisions native WebUI bindings to the renderer. The attacker can now send highly privileged IPC messages, resulting in a full Sandbox Escape.
Suggested Fix
Implement an unforgeable, cryptographically secure token mechanism for error pages. When the Browser process legitimately initiates an error page navigation, it should generate a random token, append it to the URL, and store it in the NavigationContext. The isErrorPageFileURL: (or a related check during policy decision) must verify that the token in the URL matches a valid, recently issued token by the Browser. Alternatively, strict checks should be enforced to ensure that file:// navigations to internal error pages can only occur if they are explicitly marked as Browser-initiated.
Evaluated with Chrome root at commit: cc901875d53bf4e4fe0e01f02843871da4106e70
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.