CVE-2026-17761
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ChromeWebClientios/chrome/browser/web/model/chrome_web_client.mm |
modified |
Files Changed
ios/chrome/browser/web/model/chrome_web_client.mm
Patch
From ff43855871a78f15dd8b3d5359d8e84226c3a16f Mon Sep 17 00:00:00 2001 From: Sylvain Defresne <[email protected]> Date: Thu, 25 Jun 2026 07:23:11 -0700 Subject: [PATCH] [ios] Sanitize javascript: URLs during session restoration Replace javascript: URLs by about:blank when restoring session from storage. This ensure that if unsafe URLs manages to get saved on disk or in sync, they won't be loaded. Fixed: 508249524 Change-Id: Idfb11b45195be71552723f7f9ab6beeb87dac0a7 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7976023 Reviewed-by: Mike Dougherty <[email protected]> Commit-Queue: Sylvain Defresne <[email protected]> Cr-Commit-Position: refs/heads/main@{#1652404} --- diff --git a/ios/chrome/browser/web/model/chrome_web_client.mm b/ios/chrome/browser/web/model/chrome_web_client.mm index 2c7c7ae..99da06a0 100644 --- a/ios/chrome/browser/web/model/chrome_web_client.mm +++ b/ios/chrome/browser/web/model/chrome_web_client.mm @@ -134,6 +134,7 @@ #import "ui/base/l10n/l10n_util.h" #import "ui/base/resource/resource_bundle.h" #import "url/gurl.h" +#import "url/url_constants.h" namespace { // The tag describing the product name with a placeholder for the version. @@ -283,6 +284,16 @@ version_info::GetMajorVersionNumber().c_str()); } +// Filter javascript: URLs and replace them by about:blank. +bool WillHandleWebBrowserJavascriptURLs(GURL* url, web::BrowserState*) { + if (url->is_valid() && url->SchemeIs(url::kJavaScriptScheme)) { + *url = GURL(url::kAboutBlankURL); + return true; + } + + return false; +} + } // namespace ChromeWebClient::ChromeWebClient() {} @@ -374,6 +385,7 @@ void ChromeWebClient::PostBrowserURLRewriterCreation( web::BrowserURLRewriter* rewriter) { + rewriter->AddURLRewriter(&WillHandleWebBrowserJavascriptURLs); rewriter->AddURLRewriter(&WillHandleWebBrowserNewTabPageURLForPolicy); rewriter->AddURLRewriter(&WillHandleWebBrowserAboutURL); ios::provider::AddURLRewriters(rewriter);
Original Bug Report
Potential UXSS via URL Injection in iOS Session Restore
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: The session restoration process on iOS constructs a WKWebView interactionState blob without sanitizing URLs in the NavigationItem. This allows an attacker to sync a malicious javascript: URL into a victim’s history. When the victim navigates to this history entry, the JavaScript executes in the context of the current origin, leading to a potential Universal Cross-Site Scripting (UXSS) vulnerability.
Affected files:
ios/web/navigation/synthesized_session_restore.mmios/web/navigation/navigation_manager_impl.mm
Estimated timestamp from git blame: 2021-11-18
Description
A potential Universal Cross-Site Scripting (UXSS) vulnerability exists in the session restoration mechanism of Chrome for iOS. The vulnerability stems from a lack of URL validation when constructing the WKWebView interactionState binary blob from synced session data.
The function SynthesizedSessionRestore in ios/web/navigation/synthesized_session_restore.mm creates the session state blob from a list of NavigationItem objects. It directly injects the URL string into the kEntryURL and kEntryOriginalURL properties of the state dictionary without verifying that the scheme is safe (e.g., restricting to HTTP/HTTPS/File):
[entries addObject:@{
kEntryData : entry_data.AsNSData(),
kEntryOriginalURL : base::SysUTF8ToNSString(item->GetURL().spec()),
kEntryExternalURLPolicy : external_url_policy,
kEntryTitle : base::SysUTF16ToNSString(item->GetTitle()),
kEntryURL : base::SysUTF8ToNSString(item->GetURL().spec()),
}];
This data ultimately originates from components/sync_sessions/synced_session.cc where SessionNavigationFromSyncData accepts URLs from the sync protobuf without rejecting javascript: schemes. Consequently, an attacker can sync a malicious session containing a javascript: URL.
When NavigationManagerImpl::Restore calls SynthesizedSessionRestore, the resulting blob is passed to [WKWebView setInteractionState:]. WebKit implicitly trusts the contents of this blob and populates its native history stack with the javascript: entry.
If a user opens the restored tab and performs a back/forward navigation to the malicious entry, WebKit executes the javascript: URL in the context of the currently loaded origin. Because this is a history navigation handled internally by WebKit as a script execution, it bypasses Chrome’s CRWWKNavigationHandler::decidePolicyForNavigationAction delegate, which normally blocks javascript: navigations.
Potential Attack Steps
Note: These steps are based on static analysis; a working Proof of Concept has not been verified dynamically.
- An attacker constructs a malicious
sync_pb::SessionSpecificspayload containing a tab with two history entries: a legitimate target URL (e.g.,https://example.com) and an adjacentjavascript:URL (e.g.,javascript:alert(document.domain)). - The attacker syncs this payload to their Chrome account and tricks the victim into signing in, or compromises the victim’s account to inject the payload.
- The victim’s iOS Chrome instance pulls down the synced session data.
- The victim navigates to “Recent Tabs” and opens the synced tab.
- The tab loads the legitimate URL, establishing the active document context.
- The victim interacts with the app by swiping back or clicking the back/forward button, triggering a navigation to the malicious history entry.
- WebKit executes the injected JavaScript within the context of the legitimate origin, completing the UXSS.
Suggested Fix
Sanitize URLs before encoding them into the interactionState blob. In SynthesizedSessionRestore, verify that item->GetURL().SchemeIsHTTPOrHTTPS() or use a broader allowlist of safe schemes (e.g., about:blank, chrome://). If a URL contains an unsafe scheme like javascript:, the entry should either be omitted from the restoration payload or the URL should be neutralized.
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.