Chrome · Viz
CVE-2026-106185
Input Validation in Viz
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifcontent/browser/renderer_host/render_frame_host_impl.cc |
modified | |
DidCommitTransitionReplacercontent/browser/security_exploit_browsertest.cc |
modified | |
transition_to_inject_content/browser/security_exploit_browsertest.cc |
modified | |
ifcontent/browser/security_exploit_browsertest.cc |
modified | |
SecurityExploitPageTransitionTestcontent/browser/security_exploit_browsertest.cc |
modified | |
SecurityExploitDisallowedQualifierTestcontent/browser/security_exploit_browsertest.cc |
modified | |
SecurityExploitViaDisabledWebSecurityTestcontent/browser/security_exploit_browsertest.cc |
modified |
Files Changed
content/browser/bad_message.htools/metrics/histograms/metadata/stability/enums.xmlcontent/browser/renderer_host/render_frame_host_impl.ccui/base/page_transition_types.hcomponents/sync/base/page_transition_conversion.cccontent/browser/security_exploit_browsertest.cc
Patch
From 23246e7a66e250e1221b9488c0ff3a44d83af097 Mon Sep 17 00:00:00 2001
From: Arthur Sonzogni <arthursonzogni@chromium.org>
Date: Wed, 02 Sep 2026 06:53:35 -0700
Subject: [PATCH] Enforce PageTransition validation on commit
When receiving DidCommitProvisionalLoad or
DidCommitSameDocumentNavigation from a renderer, the browser
previously accepted params->transition without validating that its core
transition type and qualifiers matched the expected frame type,
initiation source, or browser-provided parameters.
This CL adds PageTransition validation in
RenderFrameHostImpl::ValidateDidCommitParams to:
1. Verify that the PageTransition is a valid PageTransition type.
2. Verify that main frame transitions are only committed by outermost
main frames, and subframes/fenced frames commit subframe transitions.
3. Verify that renderer-initiated navigations commit web-triggerable
transitions and do not forge browser-only qualifiers (e.g.
PAGE_TRANSITION_FROM_ADDRESS_BAR).
4. Verify that browser-initiated main-frame navigations commit matching
core transition types.
Fixed: 502462485
Change-Id: Ie99423245a87e21f51ec6934b9add346db6f6cd4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8305792
Reviewed-by: Mikel Astiz <mastiz@chromium.org>
Commit-Queue: Arthur Sonzogni <arthursonzogni@chromium.org>
Reviewed-by: Roger McFarlane <rogerm@chromium.org>
Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
Reviewed-by: Dave Tapuska <dtapuska@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1690676}
---
diff --git a/components/sync/base/page_transition_conversion.cc b/components/sync/base/page_transition_conversion.cc
index e2a34ce..0118d7d 100644
--- a/components/sync/base/page_transition_conversion.cc
+++ b/components/sync/base/page_transition_conversion.cc
@@ -64,6 +64,7 @@
case ui::PAGE_TRANSITION_SERVER_REDIRECT:
case ui::PAGE_TRANSITION_IS_REDIRECT_MASK:
case ui::PAGE_TRANSITION_QUALIFIER_MASK:
+ case ui::PAGE_TRANSITION_RENDERER_DISALLOWED_QUALIFIERS_MASK:
break;
}
NOTREACHED();
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
index 83a157ae..3db4f1ec 100644
--- a/content/browser/bad_message.h
+++ b/content/browser/bad_message.h
@@ -405,6 +405,11 @@
PSI_STORAGE_ACCESS_FROM_SANDBOXED_FRAME = 377,
HSI_PLAY_HAPTICS_BLOCKED_BY_PERMISSIONS_POLICY = 378,
RFH_CREATE_CHILD_FRAME_INVALID_INITIATOR_TOKEN = 379,
+ RFH_COMMIT_NAVIGATION_INVALID_TRANSITION_TYPE = 380,
+ RFH_COMMIT_NAVIGATION_NON_WEBBY_TRANSITION = 381,
+ RFH_COMMIT_NAVIGATION_TRANSITION_FRAME_TYPE_MISMATCH = 382,
+ RFH_COMMIT_NAVIGATION_DISALLOWED_QUALIFIER = 383,
+ RFH_COMMIT_NAVIGATION_BROWSER_INITIATED_TRANSITION_MISMATCH = 384,
// Please add new elements here. The naming convention is abbreviated class
// name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 079a839..aa60250 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -16122,6 +16122,83 @@
return false;
}
+ // Validate PageTransition.
+ if (!ui::IsValidPageTransitionType(params->transition)) {
+ bad_message::ReceivedBadMessage(
+ process, bad_message::RFH_COMMIT_NAVIGATION_INVALID_TRANSITION_TYPE);
+ return false;
+ }
+
+ ui::PageTransition transition = ui::PageTransitionFromInt(params->transition);
+ bool is_main_frame = !GetParent() && !IsFencedFrameRoot();
+
+ // Main frame transitions must only be used by main frames (excluding fenced
+ // frame roots). Subframes and fenced frame roots must use subframe
+ // transitions.
+ if (ui::PageTransitionIsMainFrame(transition) != is_main_frame) {
+ bad_message::ReceivedBadMessage(
+ process,
+ bad_message::RFH_COMMIT_NAVIGATION_TRANSITION_FRAME_TYPE_MISMATCH);
+ return false;
+ }
+
+ // Fenced frame roots must only use PAGE_TRANSITION_AUTO_SUBFRAME (plus
+ // optional client redirect qualifier). Fenced frames are being removed and
+ // shouldn't be enabled by default (see crbug.com/540020472), hence a CHECK is
+ // used here instead of a bad message.
+ if (IsFencedFrameRoot()) {
+ CHECK(ui::PageTransitionCoreTypeIs(transition,
+ ui::PAGE_TRANSITION_AUTO_SUBFRAME));
+ }
+
+ // Ensure the renderer does not add privileged / browser-only qualifiers.
+ uint32_t request_qualifiers =
+ navigation_request
+ ? static_cast<uint32_t>(
+ navigation_request->common_params().transition &
+ ui::PAGE_TRANSITION_RENDERER_DISALLOWED_QUALIFIERS_MASK)
+ : 0;
+ uint32_t commit_qualifiers = static_cast<uint32_t>(
+ params->transition &
+ ui::PAGE_TRANSITION_RENDERER_DISALLOWED_QUALIFIERS_MASK);
+ if ((commit_qualifiers & ~request_qualifiers) != 0) {
+ bad_message::ReceivedBadMessage(
+ process, bad_message::RFH_COMMIT_NAVIGATION_DISALLOWED_QUALIFIER);
+ return false;
+ }
+
+ if (is_main_frame) {
+ if (!navigation_request) {
+ // For synchronous same-document navigations initiated by the renderer
+ // without a browser NavigationRequest, the transition must be
+ // web-triggerable.
+ if (!ui::PageTransitionIsWebTriggerable(transition)) {
+ bad_message::ReceivedBadMessage(
+ process, bad_message::RFH_COMMIT_NAVIGATION_NON_WEBBY_TRANSITION);
+ return false;
+ }
+ } else {
+ // For main-frame navigations where the browser provided an expected
+ // transition in NavigationRequest, the renderer must not change the core
+ // transition type (except possibly FORM_SUBMIT for POST requests).
+ ui::PageTransition expected_core_transition =
+ ui::PageTransitionStripQualifier(ui::PageTransitionFromInt(
+ navigation_request->common_params().transition));
+ bool core_type_matches =
+ ui::PageTransitionCoreTypeIs(transition, expected_core_transition) ||
+ (navigation_request->common_params().post_data &&
+ ui::PageTransitionCoreTypeIs(transition,
+ ui::PAGE_TRANSITION_FORM_SUBMIT));
+ if (!core_type_matches) {
+ bad_message::ReceivedBadMessage(
+ process,
+ bad_message::
+ RFH_COMMIT_NAVIGATION_BROWSER_INITIATED_TRANSITION_MISMATCH);
+ return false;
+ }
+ }
+ }
+
return true;
}
@@ -16387,12 +16464,6 @@
mojom::DidCommitSameDocumentNavigationParamsPtr same_document_params,
const base::TimeTicks& did_commit_ipc_received_time) {
const bool is_same_document_navigation = !!same_document_params;
- // Sanity-check the page transition for frame type. Fenced Frames
- // will set page transition to AUTO_SUBFRAME.
- // TODO(523085714): CHECK-exclusion: Convert to a CHECK once we are confident
- // it won't be triggered.
- DCHECK_EQ(ui::PageTransitionIsMainFrame(params->transition),
- !GetParent() && !IsFencedFrameRoot());
// TODO(https://crbug.com/445585641): Make this enforceable on Android.
if (navigation_request &&
navigation_request->commit_params().navigation_token !=
diff --git a/tools/metrics/histograms/metadata/stability/enums.xml b/tools/metrics/histograms/metadata/stability/enums.xml
index 509a10e..da18d59 100644
--- a/tools/metrics/histograms/metadata/stability/enums.xml
+++ b/tools/metrics/histograms/metadata/stability/enums.xml
@@ -559,6 +559,13 @@
<int value="377" label="PSI_STORAGE_ACCESS_FROM_SANDBOXED_FRAME"/>
<int value="378" label="HSI_PLAY_HAPTICS_BLOCKED_BY_PERMISSIONS_POLICY"/>
<int value="379" label="RFH_CREATE_CHILD_FRAME_INVALID_INITIATOR_TOKEN"/>
+ <int value="380" label="RFH_COMMIT_NAVIGATION_INVALID_TRANSITION_TYPE"/>
+ <int value="381" label="RFH_COMMIT_NAVIGATION_NON_WEBBY_TRANSITION"/>
+ <int value="382"
+ label="RFH_COMMIT_NAVIGATION_TRANSITION_FRAME_TYPE_MISMATCH"/>
+ <int value="383" label="RFH_COMMIT_NAVIGATION_DISALLOWED_QUALIFIER"/>
+ <int value="384"
+ label="RFH_COMMIT_NAVIGATION_BROWSER_INITIATED_TRANSITION_MISMATCH"/>
</enum>
<enum name="BadMessageReasonExtensions">
diff --git a/ui/base/page_transition_types.h b/ui/base/page_transition_types.h
index ecb5790..55d39d47 100644
--- a/ui/base/page_transition_types.h
+++ b/ui/base/page_transition_types.h
@@ -155,10 +155,18 @@
PAGE_TRANSITION_SERVER_REDIRECT = -2147483648, // 0x80000000
// Used to test whether a transition involves a redirect.
- PAGE_TRANSITION_IS_REDIRECT_MASK = -1073741824, // 0xC0000000
+ PAGE_TRANSITION_IS_REDIRECT_MASK =
+ PAGE_TRANSITION_CLIENT_REDIRECT | PAGE_TRANSITION_SERVER_REDIRECT,
// General mask defining the bits used for the qualifiers.
PAGE_TRANSITION_QUALIFIER_MASK = -256, // 0xFFFFFF00
+
+ // Mask of qualifiers that the renderer is not allowed to add unless already
+ // set by the browser.
+ PAGE_TRANSITION_RENDERER_DISALLOWED_QUALIFIERS_MASK =
+ PAGE_TRANSITION_FORWARD_BACK | PAGE_TRANSITION_FROM_ADDRESS_BAR |
+ PAGE_TRANSITION_HOME_PAGE | PAGE_TRANSITION_FROM_API |
+ PAGE_TRANSITION_SERVER_REDIRECT,
};
// Compares two PageTransition types ignoring qualifiers. |rhs| is taken to
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index a14aede2..c3d76433 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -3645,6 +3645,159 @@
}
}
+class DidCommitTransitionReplacer : public DidCommitNavigationInterceptor {
+ public:
+ DidCommitTransitionReplacer(WebContents* web_contents,
+ ui::PageTransition transition_to_inject)
+ : DidCommitNavigationInterceptor(web_contents),
+ transition_to_inject_(transition_to_inject) {}
+
+ DidCommitTransitionReplacer(const DidCommitTransitionReplacer&) = delete;
+ DidCommitTransitionReplacer& operator=(const DidCommitTransitionReplacer&) =
+ delete;
+
+ ~DidCommitTransitionReplacer() override = default;
+
+ void Activate() { is_activated_ = true; }
+
+ protected:
+ bool WillProcessDidCommitNavigation(
+ RenderFrameHost* render_frame_host,
+ NavigationRequest* navigation_request,
+ mojom::DidCommitProvisionalLoadParamsPtr* params,
+ mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
+ override {
+ if (is_activated_) {
+ (**params).transition = transition_to_inject_;
+ is_activated_ = false;
+ }
+ return true;
+ }
+
+ private:
+ ui::PageTransition transition_to_inject_;
+ bool is_activated_ = false;
+};
+
+class SecurityExploitPageTransitionTest
+ : public SecurityExploitBrowserTest,
+ public ::testing::WithParamInterface<ui::PageTransition> {};
+
+IN_PROC_BROWSER_TEST_P(SecurityExploitPageTransitionTest,
+ DidCommitNonWebbyTransition) {
+ ui::PageTransition transition = GetParam();
+ WebContents* web_contents = shell()->web_contents();
+ DidCommitTransitionReplacer injector(web_contents, transition);
+
+ GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(web_contents, main_url));
+
+ RenderProcessHost* main_process =
+ web_contents->GetPrimaryMainFrame()->GetProcess();
+ RenderProcessHostBadIpcMessageWaiter kill_waiter(main_process);
+
+ injector.Activate();
+ ExecuteScriptAsync(web_contents,
+ "history.pushState({}, '', '/title2.html');");
+
+ EXPECT_EQ(bad_message::RFH_COMMIT_NAVIGATION_NON_WEBBY_TRANSITION,
+ kill_waiter.Wait());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ All,
+ SecurityExploitPageTransitionTest,
+ ::testing::Values(ui::PAGE_TRANSITION_TYPED,
+ ui::PAGE_TRANSITION_AUTO_BOOKMARK,
+ ui::PAGE_TRANSITION_GENERATED,
+ ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
+ ui::PAGE_TRANSITION_RELOAD,
+ ui::PAGE_TRANSITION_KEYWORD,
+ ui::PAGE_TRANSITION_KEYWORD_GENERATED));
+
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
+ DidCommitBrowserInitiatedTransitionMismatch) {
+ WebContents* web_contents = shell()->web_contents();
+ DidCommitTransitionReplacer injector(web_contents,
+ ui::PAGE_TRANSITION_AUTO_BOOKMARK);
+
+ GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(web_contents, main_url));
+
+ RenderProcessHost* main_process =
+ web_contents->GetPrimaryMainFrame()->GetProcess();
+ RenderProcessHostBadIpcMessageWaiter kill_waiter(main_process);
+
+ injector.Activate();
+ ExecuteScriptAsync(web_contents, "window.location = '/title2.html';");
+
+ EXPECT_EQ(
+ bad_message::RFH_COMMIT_NAVIGATION_BROWSER_INITIATED_TRANSITION_MISMATCH,
+ kill_waiter.Wait());
+}
+
+class SecurityExploitDisallowedQualifierTest
+ : public SecurityExploitBrowserTest,
+ public ::testing::WithParamInterface<ui::PageTransition> {};
+
+IN_PROC_BROWSER_TEST_P(SecurityExploitDisallowedQualifierTest,
+ DidCommitDisallowedQualifier) {
+ ui::PageTransition transition = GetParam();
+ WebContents* web_contents = shell()->web_contents();
+ DidCommitTransitionReplacer injector(web_contents, transition);
+
+ GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(web_contents, main_url));
+
+ RenderProcessHost* main_process =
+ web_contents->GetPrimaryMainFrame()->GetProcess();
+ RenderProcessHostBadIpcMessageWaiter kill_waiter(main_process);
+
+ injector.Activate();
+ ExecuteScriptAsync(web_contents, "window.location = '/title2.html';");
+
+ EXPECT_EQ(bad_message::RFH_COMMIT_NAVIGATION_DISALLOWED_QUALIFIER,
+ kill_waiter.Wait());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ All,
+ SecurityExploitDisallowedQualifierTest,
+ ::testing::Values(
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_FROM_ADDRESS_BAR),
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_HOME_PAGE),
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_FROM_API),
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_FORWARD_BACK),
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_SERVER_REDIRECT)));
+
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
+ DidCommitInvalidTransitionForSubframe) {
+ WebContents* web_contents = shell()->web_contents();
+ DidCommitTransitionReplacer injector(web_contents, ui::PAGE_TRANSITION_LINK);
+
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)"));
+ EXPECT_TRUE(NavigateToURL(web_contents, main_url));
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(web_contents)->GetPrimaryFrameTree().root();
+ FrameTreeNode* child = root->child_at(0);
+ RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
+ RenderProcessHostBadIpcMessageWaiter kill_waiter(child_process);
+
+ injector.Activate();
+ ExecuteScriptAsync(child->current_frame_host(),
+ "window.location = '/title2.html';");
+
+ EXPECT_EQ(bad_message::RFH_COMMIT_NAVIGATION_TRANSITION_FRAME_TYPE_MISMATCH,
+ kill_waiter.Wait());
+}
+
class SecurityExploitViaDisabledWebSecurityTest
: public SecurityExploitBrowserTest {
public:
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/content/browser/security_exploit_browsertest.cc b/content/browser/security_exploit_browsertest.cc
index a14aede2..c3d76433 100644
--- a/content/browser/security_exploit_browsertest.cc
+++ b/content/browser/security_exploit_browsertest.cc
@@ -3645,6 +3645,159 @@
}
}
+class DidCommitTransitionReplacer : public DidCommitNavigationInterceptor {
+ public:
+ DidCommitTransitionReplacer(WebContents* web_contents,
+ ui::PageTransition transition_to_inject)
+ : DidCommitNavigationInterceptor(web_contents),
+ transition_to_inject_(transition_to_inject) {}
+
+ DidCommitTransitionReplacer(const DidCommitTransitionReplacer&) = delete;
+ DidCommitTransitionReplacer& operator=(const DidCommitTransitionReplacer&) =
+ delete;
+
+ ~DidCommitTransitionReplacer() override = default;
+
+ void Activate() { is_activated_ = true; }
+
+ protected:
+ bool WillProcessDidCommitNavigation(
+ RenderFrameHost* render_frame_host,
+ NavigationRequest* navigation_request,
+ mojom::DidCommitProvisionalLoadParamsPtr* params,
+ mojom::DidCommitProvisionalLoadInterfaceParamsPtr* interface_params)
+ override {
+ if (is_activated_) {
+ (**params).transition = transition_to_inject_;
+ is_activated_ = false;
+ }
+ return true;
+ }
+
+ private:
+ ui::PageTransition transition_to_inject_;
+ bool is_activated_ = false;
+};
+
+class SecurityExploitPageTransitionTest
+ : public SecurityExploitBrowserTest,
+ public ::testing::WithParamInterface<ui::PageTransition> {};
+
+IN_PROC_BROWSER_TEST_P(SecurityExploitPageTransitionTest,
+ DidCommitNonWebbyTransition) {
+ ui::PageTransition transition = GetParam();
+ WebContents* web_contents = shell()->web_contents();
+ DidCommitTransitionReplacer injector(web_contents, transition);
+
+ GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(web_contents, main_url));
+
+ RenderProcessHost* main_process =
+ web_contents->GetPrimaryMainFrame()->GetProcess();
+ RenderProcessHostBadIpcMessageWaiter kill_waiter(main_process);
+
+ injector.Activate();
+ ExecuteScriptAsync(web_contents,
+ "history.pushState({}, '', '/title2.html');");
+
+ EXPECT_EQ(bad_message::RFH_COMMIT_NAVIGATION_NON_WEBBY_TRANSITION,
+ kill_waiter.Wait());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ All,
+ SecurityExploitPageTransitionTest,
+ ::testing::Values(ui::PAGE_TRANSITION_TYPED,
+ ui::PAGE_TRANSITION_AUTO_BOOKMARK,
+ ui::PAGE_TRANSITION_GENERATED,
+ ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
+ ui::PAGE_TRANSITION_RELOAD,
+ ui::PAGE_TRANSITION_KEYWORD,
+ ui::PAGE_TRANSITION_KEYWORD_GENERATED));
+
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
+ DidCommitBrowserInitiatedTransitionMismatch) {
+ WebContents* web_contents = shell()->web_contents();
+ DidCommitTransitionReplacer injector(web_contents,
+ ui::PAGE_TRANSITION_AUTO_BOOKMARK);
+
+ GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(web_contents, main_url));
+
+ RenderProcessHost* main_process =
+ web_contents->GetPrimaryMainFrame()->GetProcess();
+ RenderProcessHostBadIpcMessageWaiter kill_waiter(main_process);
+
+ injector.Activate();
+ ExecuteScriptAsync(web_contents, "window.location = '/title2.html';");
+
+ EXPECT_EQ(
+ bad_message::RFH_COMMIT_NAVIGATION_BROWSER_INITIATED_TRANSITION_MISMATCH,
+ kill_waiter.Wait());
+}
+
+class SecurityExploitDisallowedQualifierTest
+ : public SecurityExploitBrowserTest,
+ public ::testing::WithParamInterface<ui::PageTransition> {};
+
+IN_PROC_BROWSER_TEST_P(SecurityExploitDisallowedQualifierTest,
+ DidCommitDisallowedQualifier) {
+ ui::PageTransition transition = GetParam();
+ WebContents* web_contents = shell()->web_contents();
+ DidCommitTransitionReplacer injector(web_contents, transition);
+
+ GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+ EXPECT_TRUE(NavigateToURL(web_contents, main_url));
+
+ RenderProcessHost* main_process =
+ web_contents->GetPrimaryMainFrame()->GetProcess();
+ RenderProcessHostBadIpcMessageWaiter kill_waiter(main_process);
+
+ injector.Activate();
+ ExecuteScriptAsync(web_contents, "window.location = '/title2.html';");
+
+ EXPECT_EQ(bad_message::RFH_COMMIT_NAVIGATION_DISALLOWED_QUALIFIER,
+ kill_waiter.Wait());
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ All,
+ SecurityExploitDisallowedQualifierTest,
+ ::testing::Values(
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_FROM_ADDRESS_BAR),
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_HOME_PAGE),
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_FROM_API),
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_FORWARD_BACK),
+ static_cast<ui::PageTransition>(ui::PAGE_TRANSITION_LINK |
+ ui::PAGE_TRANSITION_SERVER_REDIRECT)));
+
+IN_PROC_BROWSER_TEST_F(SecurityExploitBrowserTest,
+ DidCommitInvalidTransitionForSubframe) {
+ WebContents* web_contents = shell()->web_contents();
+ DidCommitTransitionReplacer injector(web_contents, ui::PAGE_TRANSITION_LINK);
+
+ GURL main_url(embedded_test_server()->GetURL(
+ "a.com", "/cross_site_iframe_factory.html?a(a)"));
+ EXPECT_TRUE(NavigateToURL(web_contents, main_url));
+
+ FrameTreeNode* root =
+ static_cast<WebContentsImpl*>(web_contents)->GetPrimaryFrameTree().root();
+ FrameTreeNode* child = root->child_at(0);
+ RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
+ RenderProcessHostBadIpcMessageWaiter kill_waiter(child_process);
+
+ injector.Activate();
+ ExecuteScriptAsync(child->current_frame_host(),
+ "window.location = '/title2.html';");
+
+ EXPECT_EQ(bad_message::RFH_COMMIT_NAVIGATION_TRANSITION_FRAME_TYPE_MISMATCH,
+ kill_waiter.Wait());
+}
+
class SecurityExploitViaDisabledWebSecurityTest
: public SecurityExploitBrowserTest {
public:
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.
References
On This Page