CVE-2026-11243
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
TEST_Fchrome/browser/download/chrome_download_manager_delegate_unittest.cc |
modified | |
forchrome/browser/download/chrome_download_manager_delegate_unittest.cc |
modified |
Files Changed
chrome/browser/download/chrome_download_manager_delegate_unittest.ccchrome/browser/download/insecure_download_blocking.cc
Patch
From 0b7e6fe4e01ec65708ab649386e79401d786fe04 Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner <[email protected]> Date: Thu, 30 Apr 2026 09:08:27 -0700 Subject: [PATCH] Fix bitwise logic error in insecure download blocking The core PageTransition values are sequential integers, not mutually exclusive bitmasks. Using bitwise AND on these values (like TYPED, AUTO_SUBFRAME, FORM_SUBMIT) led to incorrect classification of navigation types, causing attacker-controlled downloads to bypass mixed-content blocking. This bug was introduced in crrev.com/c/1962532, which did not add test coverage for these transition types. This CL replaces bitwise AND operations with ui::PageTransitionCoreTypeIs() for core transition types. Qualifiers continue to use bitwise AND. Fixed: 497394061 Change-Id: Ic77becef0f68497da0f744248594653aa87d2cbf Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7807927 Commit-Queue: Andrew Paseltiner <[email protected]> Reviewed-by: Xinghui Lu <[email protected]> Cr-Commit-Position: refs/heads/main@{#1623256} --- diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc index 20fd3da0..7976113 100644 --- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc +++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc @@ -1591,6 +1591,39 @@ } } +// Regression test for crbug.com/497394061. PageTransition core values are +// sequential integers, not bitmasks. This test ensures that transition types +// like AUTO_SUBFRAME and FORM_SUBMIT are not incorrectly flagged as TYPED or +// RELOAD due to bitwise logic errors, which would cause a security downgrade +// for mixed-content downloads. +TEST_F(ChromeDownloadManagerDelegateTest, InsecureDownloadsBlocked_Regression) { + const GURL kInsecureFile("http://example.com/foo"); + const auto kSecureOrigin = Origin::Create(GURL("https://example.org")); + + // Regression test for bitwise logic error in PageTransition core types. + // PAGE_TRANSITION_AUTO_SUBFRAME (3) and PAGE_TRANSITION_FORM_SUBMIT (7) + // should not be incorrectly flagged as TYPED (1) or RELOAD (8). + const ui::PageTransition kTransitionTypes[] = { + ui::PAGE_TRANSITION_AUTO_SUBFRAME, + ui::PAGE_TRANSITION_FORM_SUBMIT, + }; + + for (auto transition_type : kTransitionTypes) { + std::unique_ptr<download::MockDownloadItem> download_item = + PrepareDownloadItemForInsecureBlocking(kInsecureFile, kSecureOrigin, + std::nullopt); + ON_CALL(*download_item, GetTransitionType()) + .WillByDefault(::testing::Return(transition_type)); + + download::DownloadTargetInfo target_info = + DetermineDownloadTarget(download_item.get()); + + EXPECT_EQ(download::DownloadItem::InsecureDownloadStatus::SILENT_BLOCK, + target_info.insecure_download_status) + << "Failed for transition type: " << transition_type; + } +} + // Verify that insecure downloads not blocked normally are blocked when // HTTPS-First mode is enabled. TEST_F(ChromeDownloadManagerDelegateTest, diff --git a/chrome/browser/download/insecure_download_blocking.cc b/chrome/browser/download/insecure_download_blocking.cc index b79cb91..cfedddb9 100644 --- a/chrome/browser/download/insecure_download_blocking.cc +++ b/chrome/browser/download/insecure_download_blocking.cc @@ -218,12 +218,16 @@ auto download_source = item->GetDownloadSource(); auto transition_type = item->GetTransitionType(); if (download_source == DownloadSource::RETRY || - (transition_type & ui::PAGE_TRANSITION_RELOAD) || - (transition_type & ui::PAGE_TRANSITION_TYPED) || + ui::PageTransitionCoreTypeIs(transition_type, + ui::PAGE_TRANSITION_RELOAD) || + ui::PageTransitionCoreTypeIs(transition_type, + ui::PAGE_TRANSITION_TYPED) || (transition_type & ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) || (transition_type & ui::PAGE_TRANSITION_FORWARD_BACK) || - (transition_type & ui::PAGE_TRANSITION_AUTO_TOPLEVEL) || - (transition_type & ui::PAGE_TRANSITION_AUTO_BOOKMARK) || + ui::PageTransitionCoreTypeIs(transition_type, + ui::PAGE_TRANSITION_AUTO_TOPLEVEL) || + ui::PageTransitionCoreTypeIs(transition_type, + ui::PAGE_TRANSITION_AUTO_BOOKMARK) || (transition_type & ui::PAGE_TRANSITION_FROM_API) || download_source == DownloadSource::OFFLINE_PAGE || download_source == DownloadSource::INTERNAL_API || @@ -254,7 +258,8 @@ // downloads. For example, downloads are blocked even if they're initiated // from the omnibox. if (download_source == DownloadSource::RETRY || - (transition_type & ui::PAGE_TRANSITION_RELOAD) || + ui::PageTransitionCoreTypeIs(transition_type, + ui::PAGE_TRANSITION_RELOAD) || (transition_type & ui::PAGE_TRANSITION_FROM_API) || download_source == DownloadSource::OFFLINE_PAGE || download_source == DownloadSource::INTERNAL_API ||
Regression Test / PoC
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
index 20fd3da0..7976113 100644
--- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -1591,6 +1591,39 @@
}
}
+// Regression test for crbug.com/497394061. PageTransition core values are
+// sequential integers, not bitmasks. This test ensures that transition types
+// like AUTO_SUBFRAME and FORM_SUBMIT are not incorrectly flagged as TYPED or
+// RELOAD due to bitwise logic errors, which would cause a security downgrade
+// for mixed-content downloads.
+TEST_F(ChromeDownloadManagerDelegateTest, InsecureDownloadsBlocked_Regression) {
+ const GURL kInsecureFile("http://example.com/foo");
+ const auto kSecureOrigin = Origin::Create(GURL("https://example.org"));
+
+ // Regression test for bitwise logic error in PageTransition core types.
+ // PAGE_TRANSITION_AUTO_SUBFRAME (3) and PAGE_TRANSITION_FORM_SUBMIT (7)
+ // should not be incorrectly flagged as TYPED (1) or RELOAD (8).
+ const ui::PageTransition kTransitionTypes[] = {
+ ui::PAGE_TRANSITION_AUTO_SUBFRAME,
+ ui::PAGE_TRANSITION_FORM_SUBMIT,
+ };
+
+ for (auto transition_type : kTransitionTypes) {
+ std::unique_ptr<download::MockDownloadItem> download_item =
+ PrepareDownloadItemForInsecureBlocking(kInsecureFile, kSecureOrigin,
+ std::nullopt);
+ ON_CALL(*download_item, GetTransitionType())
+ .WillByDefault(::testing::Return(transition_type));
+
+ download::DownloadTargetInfo target_info =
+ DetermineDownloadTarget(download_item.get());
+
+ EXPECT_EQ(download::DownloadItem::InsecureDownloadStatus::SILENT_BLOCK,
+ target_info.insecure_download_status)
+ << "Failed for transition type: " << transition_type;
+ }
+}
+
// Verify that insecure downloads not blocked normally are blocked when
// HTTPS-First mode is enabled.
TEST_F(ChromeDownloadManagerDelegateTest,
Original Bug Report
Security UI downgrade in mixed downloads due to PageTransition bitwise logic error
Project Fortify, an experimental security project, has identified the following potential security issue.
Overview: A bitwise logic error in insecure download blocking incorrectly evaluates PageTransition core values as bitmasks rather than sequential integers. This causes attacker-controlled navigations (like form submissions or subframes) to incorrectly bypass mixed-content checks. Consequently, an intended hard block (SILENT_BLOCK) for dangerous files is downgraded to a bypassable UI warning (BLOCK).
Affected files:
chrome/browser/download/insecure_download_blocking.ccui/base/page_transition_types.h
Estimated timestamp from git blame: 2022-12-29
Description
There is a potential security downgrade in Chrome’s mixed-content download blocking logic.
In chrome/browser/download/insecure_download_blocking.cc, the InsecureDownloadData constructor determines if a download should be exempt from mixed-content blocking by checking its transition_type against several ui::PageTransition values using bitwise AND (&) operations:
if (download_source == DownloadSource::RETRY ||
(transition_type & ui::PAGE_TRANSITION_RELOAD) ||
(transition_type & ui::PAGE_TRANSITION_TYPED) ||
// ...
However, as defined in ui/base/page_transition_types.h, the core PageTransition values (like PAGE_TRANSITION_TYPED = 1, PAGE_TRANSITION_AUTO_SUBFRAME = 3, PAGE_TRANSITION_AUTO_TOPLEVEL = 6, and PAGE_TRANSITION_FORM_SUBMIT = 7) are sequential integers, not mutually exclusive bitmasks. The core transition type is stored in the lower 8 bits (mask 0xFF).
Because of this, any core transition type that shares bits with the checked values will incorrectly evaluate to true. For example:
- A form submission (
PAGE_TRANSITION_FORM_SUBMIT, value 7) bitwise-ANDed withPAGE_TRANSITION_TYPED(value 1) evaluates to 1 (truthy). - An automatic subframe navigation (
PAGE_TRANSITION_AUTO_SUBFRAME, value 3) bitwise-ANDed withPAGE_TRANSITION_TYPED(value 1) evaluates to 1 (truthy).
When this evaluates to true, is_mixed_content_ is incorrectly set to false. Later in GetInsecureDownloadStatusForDownload(), if is_insecure_download_ is true but is_mixed_content_ is false, the function early-returns InsecureDownloadStatus::BLOCK. This skips the stricter mixed-content logic that would otherwise return InsecureDownloadStatus::SILENT_BLOCK for dangerous file types.
Potential Attacker Steps
Note: These are potential steps to trigger the vulnerability, as our tooling agent does not have the ability to run code to produce a working PoC.
- An attacker sets up an HTTPS-hosted webpage that they control.
- The attacker embeds an
iframewith asrcpointing to a malicious executable payload hosted on an insecure HTTP origin (e.g.,http://attacker.com/malware.exe), OR uses an HTML form targeting the same HTTP URL. - The victim visits the HTTPS page. The iframe attempts to load, or the victim is tricked into submitting the form.
- The navigation is converted into a download. The download inherits the transition type
PAGE_TRANSITION_AUTO_SUBFRAME(3) orPAGE_TRANSITION_FORM_SUBMIT(7). - Due to the bitwise logic error (
3 & 1 == 1or7 & 1 == 1), Chrome incorrectly flagsis_mixed_content_ = false. - The download is flagged as
BLOCKinstead ofSILENT_BLOCK. The user sees a visible “Keep / Discard” warning and can bypass the mixed-content protection to save the malware.
Suggested Fix
Replace the bitwise AND operations for core transition types with the ui::PageTransitionCoreTypeIs() helper function, which correctly masks and compares the core type.
if (download_source == DownloadSource::RETRY ||
ui::PageTransitionCoreTypeIs(transition_type, ui::PAGE_TRANSITION_RELOAD) ||
ui::PageTransitionCoreTypeIs(transition_type, ui::PAGE_TRANSITION_TYPED) ||
ui::PageTransitionCoreTypeIs(transition_type, ui::PAGE_TRANSITION_FROM_ADDRESS_BAR) ||
ui::PageTransitionCoreTypeIs(transition_type, ui::PAGE_TRANSITION_FORWARD_BACK) ||
ui::PageTransitionCoreTypeIs(transition_type, ui::PAGE_TRANSITION_AUTO_TOPLEVEL) ||
ui::PageTransitionCoreTypeIs(transition_type, ui::PAGE_TRANSITION_AUTO_BOOKMARK) ||
// Note: PAGE_TRANSITION_FROM_API is a qualifier (0x08000000), so bitwise AND is correct here.
(transition_type & ui::PAGE_TRANSITION_FROM_API) ||
// ...
Ensure that this correction is applied to all instances where core page transition types are checked in insecure_download_blocking.cc.
Evaluated with Chrome root at commit: a9cbf6e8b275fe4147435aa905f3b7f5a656f5f0
Results from 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.