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 <[email protected]> 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 <[email protected]> Commit-Queue: Arthur Sonzogni <[email protected]> Reviewed-by: Roger McFarlane <[email protected]> Reviewed-by: Mitsuru Oshima <[email protected]> Reviewed-by: Dave Tapuska <[email protected]> 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