Chrome · Downloads
CVE-2026-87465
Logic Error in Downloads
Overview
Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Files Changed
content/browser/download/download_browsertest.cccontent/browser/renderer_host/render_frame_host_impl.ccthird_party/blink/public/mojom/frame/frame.mojomthird_party/blink/renderer/core/frame/local_frame.ccthird_party/blink/renderer/core/html/media/html_video_element.ccthird_party/blink/renderer/core/html/media/html_video_element_test.cc
Patch
From 0d84f06e082c9d50591ae52473a1f8afbd6985df Mon Sep 17 00:00:00 2001 From: Svend L <[email protected]> Date: Fri, 14 Aug 2026 11:15:45 -0700 Subject: [PATCH] [Downloads] Rename is_context_menu_save to should_prompt_for_save_location After crrev.com/c/8177729, DownloadURLParams::is_context_menu_save is only used to determine whether the filepicker should be shown for a download. Since the param is supplied by the renderer, a compromised renderer can lie about whether a download is initiated from a context menu. Rename the param to reflect its narrower scope, and to discourage the browser from relying on the param value to indicate download source in the future. Bug: 496616790 Change-Id: Ic5a1277c2ded0671b3f72f9ae004d81a6a6a6964 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8204664 Reviewed-by: Charlie Reis <[email protected]> Reviewed-by: Giovanni Ortuno Urquidi <[email protected]> Reviewed-by: Nate Chapin <[email protected]> Reviewed-by: Ari Chivukula <[email protected]> Reviewed-by: Min Qin <[email protected]> Commit-Queue: Svend L <[email protected]> Cr-Commit-Position: refs/heads/main@{#1679710} --- diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc index 5f0208a..9e57315f 100644 --- a/content/browser/download/download_browsertest.cc +++ b/content/browser/download/download_browsertest.cc @@ -5446,7 +5446,7 @@ auto params = blink::mojom::DownloadURLParams::New(); params->url = kDownloadUrl; - params->is_context_menu_save = true; + params->should_prompt_for_save_location = true; static_cast<RenderFrameHostImpl*>(render_frame_host) ->DownloadURL(std::move(params)); @@ -5520,7 +5520,7 @@ auto params = blink::mojom::DownloadURLParams::New(); params->url = kDownloadUrl; - params->is_context_menu_save = true; + params->should_prompt_for_save_location = true; static_cast<RenderFrameHostImpl*>(fenced_frame_host) ->DownloadURL(std::move(params)); diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index e038883..c8440e1 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc @@ -8003,14 +8003,13 @@ std::unique_ptr<download::DownloadUrlParameters> parameters = CreateDownloadUrlParameters(blink_parameters->url, traffic_annotation); // Downloads arriving through this IPC handler always originate from web - // content, so treat them as content-initiated regardless of what the - // renderer reports in `is_context_menu_save`. + // content. parameters->set_content_initiated(true); parameters->set_has_user_gesture(blink_parameters->has_user_gesture && HasTransientUserActivation()); parameters->set_suggested_name( blink_parameters->suggested_name.value_or(std::u16string())); - parameters->set_prompt(blink_parameters->is_context_menu_save); + parameters->set_prompt(blink_parameters->should_prompt_for_save_location); parameters->set_cross_origin_redirects( blink_parameters->cross_origin_redirects); parameters->set_referrer( diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom index 5db65454..579f2fd 100644 --- a/third_party/blink/public/mojom/frame/frame.mojom +++ b/third_party/blink/public/mojom/frame/frame.mojom @@ -142,8 +142,8 @@ // Non-null when |url| is for "data:", eg. when saving an image. pending_remote<Blob>? data_url_blob; - // Whether the download is from context menu. - bool is_context_menu_save = false; + // Whether to prompt the user for a destination filepath. + bool should_prompt_for_save_location = false; // True when the download was preceded by a recent gesture from the user. bool has_user_gesture = false; diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 43eb225..f049ab6f 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc @@ -3867,7 +3867,7 @@ } auto params = mojom::blink::DownloadURLParams::New(); - params->is_context_menu_save = true; + params->should_prompt_for_save_location = true; params->data_url_blob = DataURLToBlob(url); GetLocalFrameHostRemote().DownloadURL(std::move(params)); } diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc index d47b1d93..e07540f 100644 --- a/third_party/blink/renderer/core/html/media/html_video_element.cc +++ b/third_party/blink/renderer/core/html/media/html_video_element.cc @@ -574,7 +574,7 @@ /*is_top_level_navigation=*/false); auto params = mojom::blink::DownloadURLParams::New(); - params->is_context_menu_save = true; + params->should_prompt_for_save_location = true; auto timestamp_ms = base::saturated_cast<uint32_t>( currentTime() * base::Time::kMillisecondsPerSecond); params->suggested_name = diff --git a/third_party/blink/renderer/core/html/media/html_video_element_test.cc b/third_party/blink/renderer/core/html/media/html_video_element_test.cc index 18d3482b..e7bfeee 100644 --- a/third_party/blink/renderer/core/html/media/html_video_element_test.cc +++ b/third_party/blink/renderer/core/html/media/html_video_element_test.cc @@ -710,7 +710,7 @@ ASSERT_TRUE(FrameHost()->download_url_called()); const auto& params = FrameHost()->download_params(); ASSERT_TRUE(params); - EXPECT_TRUE(params->is_context_menu_save); + EXPECT_TRUE(params->should_prompt_for_save_location); EXPECT_TRUE(params->suggested_name.starts_with("videoframe_")); EXPECT_TRUE(params->url.ProtocolIs("blob")); EXPECT_TRUE(params->blob_url_token.is_valid());
Loading diff…
Regression Test / PoC
shipped with the fix
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 5f0208a..9e57315f 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -5446,7 +5446,7 @@
auto params = blink::mojom::DownloadURLParams::New();
params->url = kDownloadUrl;
- params->is_context_menu_save = true;
+ params->should_prompt_for_save_location = true;
static_cast<RenderFrameHostImpl*>(render_frame_host)
->DownloadURL(std::move(params));
@@ -5520,7 +5520,7 @@
auto params = blink::mojom::DownloadURLParams::New();
params->url = kDownloadUrl;
- params->is_context_menu_save = true;
+ params->should_prompt_for_save_location = true;
static_cast<RenderFrameHostImpl*>(fenced_frame_host)
->DownloadURL(std::move(params));
diff --git a/third_party/blink/renderer/core/html/media/html_video_element_test.cc b/third_party/blink/renderer/core/html/media/html_video_element_test.cc
index 18d3482b..e7bfeee 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element_test.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element_test.cc
@@ -710,7 +710,7 @@
ASSERT_TRUE(FrameHost()->download_url_called());
const auto& params = FrameHost()->download_params();
ASSERT_TRUE(params);
- EXPECT_TRUE(params->is_context_menu_save);
+ EXPECT_TRUE(params->should_prompt_for_save_location);
EXPECT_TRUE(params->suggested_name.starts_with("videoframe_"));
EXPECT_TRUE(params->url.ProtocolIs("blob"));
EXPECT_TRUE(params->blob_url_token.is_valid());
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