CVE-2026-13974
Overview
Changed Functions
| Function | Change | Notes |
|---|---|---|
ifchrome/utility/safe_browsing/mac/hfs.cc |
modified |
Files Changed
chrome/utility/safe_browsing/mac/hfs.cc
Patch
From c67ee228a39a90254f3447ce4951fb044dbb92ea Mon Sep 17 00:00:00 2001 From: Andrew Paseltiner <[email protected]> Date: Wed, 27 May 2026 08:06:08 -0700 Subject: [PATCH] Fix 32-bit integer overflow in HFS+ B-tree parser In HFSBTreeIterator::SeekToNode, the calculation of the node offset was performed using 32-bit unsigned arithmetic before being assigned to a 64-bit size_t. For node IDs at or above 4 GiB, this resulted in an overflow/wrap-around, allowing malicious files to be hidden from Safe Browsing scanning. This CL fixes the overflow by using base::CheckedNumeric<off_t> for the calculation and safely assigning it with AssignIfValid. Fixed: 513850475 Change-Id: I23050b408b25c9a22cab27ba492abb319d6151e1 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7876765 Reviewed-by: thefrog <[email protected]> Commit-Queue: Andrew Paseltiner <[email protected]> Cr-Commit-Position: refs/heads/main@{#1636962} --- diff --git a/chrome/utility/safe_browsing/mac/hfs.cc b/chrome/utility/safe_browsing/mac/hfs.cc index 12c6484..bf214ab0 100644 --- a/chrome/utility/safe_browsing/mac/hfs.cc +++ b/chrome/utility/safe_browsing/mac/hfs.cc @@ -699,14 +699,20 @@ } bool HFSBTreeIterator::SeekToNode(uint32_t node_id) { - if (node_id >= header_.totalNodes) + if (node_id >= header_.totalNodes) { return false; - size_t offset = node_id * header_.nodeSize; - if (stream_->Seek(offset, SEEK_SET) != -1) { - current_leaf_number_ = node_id; - return true; } - return false; + + base::CheckedNumeric<off_t> safe_offset = node_id; + safe_offset *= header_.nodeSize; + + if (off_t offset; !safe_offset.AssignIfValid(&offset) || + stream_->Seek(offset, SEEK_SET) == -1) { + return false; + } + + current_leaf_number_ = node_id; + return true; } bool HFSBTreeIterator::ReadCurrentLeaf() {
Original Bug Report
Potential Safe Browsing bypass in DMG parser due to 32-bit integer overflow
Project Fortify, 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. Please see https://chromium.googlesource.com/chromium/src/+/main/docs/security/ai-generated-security-bugs-faq.md for more information.
Overview: A 32-bit integer overflow in Chromium’s HFS+ B-tree parser allows an attacker to hide malicious files within a DMG to bypass Safe Browsing scanning. By placing file records at offsets exceeding 4 GiB, the scanner’s node offset calculation wraps around, causing the analysis to skip malicious content while it remains accessible to macOS.
Affected files:
chrome/utility/safe_browsing/mac/hfs.ccchrome/utility/safe_browsing/mac/dmg_analyzer.ccchrome/utility/safe_browsing/mac/udif.ccchrome/services/file_util/safe_archive_analyzer.cc
Estimated timestamp from git blame: Unknown (Google3 checkout)
Potential Vulnerability: Safe Browsing DMG Scanning Bypass
A potential 32-bit integer overflow vulnerability exists in Chromium’s HFS+ catalog B-tree parser, which is used by the Safe Browsing utility to analyze DMG files on macOS. This overflow can be leveraged by an attacker to create a ‘differential parsing’ scenario where Chromium fails to detect malicious files that are correctly identified and executed by the macOS kernel upon mounting the DMG.
Root Cause Analysis
In chrome/utility/safe_browsing/mac/hfs.cc, the method HFSBTreeIterator::SeekToNode calculates the byte offset of a B-tree node using 32-bit arithmetic before assigning it to a 64-bit size_t:
// chrome/utility/safe_browsing/mac/hfs.cc:704
bool HFSBTreeIterator::SeekToNode(uint32_t node_id) {
if (node_id >= header_.totalNodes)
return false;
size_t offset = node_id * header_.nodeSize; // Potential overflow
if (stream_->Seek(offset, SEEK_SET) != -1) {
current_leaf_number_ = node_id;
return true;
}
return false;
}
node_id is a uint32_t and header_.nodeSize is a uint16_t. In C++, the multiplication node_id * header_.nodeSize is performed using 32-bit unsigned arithmetic (after integral promotion of the uint16_t). If the resulting byte offset is 4 GiB ($2^{32}$ bytes) or greater, the product will wrap around modulo $2^{32}$.
For example, with a standard HFS+ node size of 4096 bytes, any node_id greater than or equal to 1,048,576 will result in an overflow. An offset of exactly 4 GiB will wrap to 0, causing the parser to seek to the beginning of the Catalog File fork (the header node) instead of the intended leaf node.
Potential Impact
This vulnerability allows an attacker to deterministicly bypass Safe Browsing download scanning for DMG files. By placing malicious Mach-O binaries at logical offsets exceeding 4 GiB in the HFS+ Catalog B-tree, Chromium’s scanner will encounter the overflow, seek to the wrong location, and fail to find the malicious records. This leads the scanner to report the archive as safe. However, the macOS kernel uses 64-bit offsets for filesystem I/O and will correctly identify and present the malicious files to the user once the DMG is mounted.
This issue occurs in the sandboxed utility process and does not directly lead to memory corruption or arbitrary code execution within the sandbox; rather, it is a logic-based security bypass that degrades Chrome’s defense-in-depth.
Suggested Potential Steps to Trigger
- Craft a Malicious DMG: Use UDIF
ZERO_FILLchunks to create a DMG with a logical size exceeding 4 GiB while maintaining a small file size for distribution. - Populate HFS+ Catalog: Construct an HFS+ Catalog B-tree such that the records for malicious binaries are located in nodes with IDs that trigger the $2^{32}$ overflow (e.g.,
node_id * nodeSize >= 4,294,967,296). - Bypass Scanning: When the DMG is downloaded in Chrome, the
SafeArchiveAnalyzerwill skip these high-offset nodes due to the seek error, resulting in a safe verdict.
Suggested Fix
Ensure that the offset calculation is performed using 64-bit arithmetic. Using Chromium’s base::CheckedNumeric is recommended to also catch potential 64-bit overflows:
auto offset = base::CheckedNumeric<uint64_t>(node_id) * header_.nodeSize;
if (!offset.IsValid() || stream_->Seek(offset.ValueOrDie(), SEEK_SET) == -1) {
return false;
}
Additionally, validation should be added to ensure that the calculated offset does not exceed the logical size of the Catalog File fork.
Evaluated with Chrome root at commit: 1a8d40fc44df2088d5945c0bf53584038aa1614a
Results so far have been promising, but there can be wrong deductions. Feel free to adjust as follows:
- If you are familiar with the severity guidelines, you may adjust the severity.
- If this is a false positive, and there’s no work to be done, please close as WAI.
- If there is work to do here but not a vulnerability, please change the issue type to Task/Bug/FR.
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.