CVE-2026-10015
Overview
Files Changed
third_party/blink/renderer/platform/wtf/vector.h
Patch
From ddf427ac6b17eb7fc8ffb41adbac960acbe4d73d Mon Sep 17 00:00:00 2001
From: Kent Tamura <tkent@chromium.org>
Date: Tue, 19 May 2026 20:03:50 -0700
Subject: [PATCH] WTF: Use base::checked_cast for size casting in Vector constructors
Initializing a blink::Vector from a base::span or a range uses size_t
for the input size, but blink::Vector internally uses wtf_size_t
(32-bit) for its size representation.
This change introduces base::checked_cast<wtf_size_t> during
construction to ensure that if the input size exceeds the 32-bit limit,
the process crashes safely. This prevents silent integer truncation,
which could otherwise lead to memory safety issues such as buffer
overflows.
No unit tests are added because it is impractical to allocate a 4GB+
buffer to trigger this condition in a standard test environment.
Bug: 514746176
Change-Id: Iff0edf2a1ce40da294c77f9c5eeb5898ac56611b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7861980
Reviewed-by: Kentaro Hara <haraken@chromium.org>
Commit-Queue: Kent Tamura <tkent@chromium.org>
Auto-Submit: Kent Tamura <tkent@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1633311}
---
diff --git a/third_party/blink/renderer/platform/wtf/vector.h b/third_party/blink/renderer/platform/wtf/vector.h
index e5ae4f4..b1274e3f 100644
--- a/third_party/blink/renderer/platform/wtf/vector.h
+++ b/third_party/blink/renderer/platform/wtf/vector.h
@@ -1876,9 +1876,9 @@
template <typename T, wtf_size_t InlineCapacity, typename Allocator>
template <typename U>
Vector<T, InlineCapacity, Allocator>::Vector(base::span<const U> other)
- : Base(other.size()) {
+ : Base(base::checked_cast<wtf_size_t>(other.size())) {
UNSAFE_TODO(ANNOTATE_NEW_BUFFER(data(), capacity(), other.size()));
- size_ = other.size();
+ size_ = base::checked_cast<wtf_size_t>(other.size());
TypeOperations::UninitializedCopy(other, base::span(*this),
VectorOperationOrigin::kConstruction);
}
@@ -1887,7 +1887,7 @@
template <typename Range, typename Proj>
requires VectorCanAssignFromRange<T, InlineCapacity, Allocator, Range, Proj>
Vector<T, InlineCapacity, Allocator>::Vector(Range&& other, Proj proj)
- : Base(std::ranges::size(other)) {
+ : Base(base::checked_cast<wtf_size_t>(std::ranges::size(other))) {
// Note that `size(other)` may become smaller if `other` is a hash table
// with WeakMember keys and `Base(size(other))` above caused GC which
// removed some entries from `other`, see crbug.com/40448463. This won't
@@ -1898,7 +1898,7 @@
TypeOperations::UninitializedTransform(
std::ranges::begin(other), std::ranges::end(other), data(),
VectorOperationOrigin::kConstruction, std::move(proj));
- size_ = std::ranges::size(other);
+ size_ = base::checked_cast<wtf_size_t>(std::ranges::size(other));
}
template <typename T, wtf_size_t InlineCapacity, typename Allocator>
Original Bug Report
Potential heap overflow in WTF::Vector constructor due to integer truncation
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 64-to-32-bit integer truncation in the WTF::Vector constructor when initialized from a base::span results in an undersized buffer allocation. This leads to a potential linear heap buffer overflow of attacker-controlled data during the subsequent copy operation. The issue is reachable from JavaScript via the IndexedDB API using large ArrayBuffers.
Affected files:
third_party/blink/renderer/platform/wtf/vector.hthird_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc
Estimated timestamp from git blame: 2025-10-24
Description
A potential integer truncation vulnerability exists in the WTF::Vector constructor on 64-bit platforms. When a WTF::Vector is constructed from a base::span, the size of the span (a 64-bit size_t) is implicitly truncated to a 32-bit wtf_size_t (uint32_t) during buffer allocation and when setting the vector’s size_ member. This narrowing occurs without a base::checked_cast or any bounds validation.
The vulnerable code in third_party/blink/renderer/platform/wtf/vector.h is:
template <typename T, wtf_size_t InlineCapacity, typename Allocator>
template <typename U>
Vector<T, InlineCapacity, Allocator>::Vector(base::span<const U> other)
: Base(other.size()) {
UNSAFE_TODO(ANNOTATE_NEW_BUFFER(data(), capacity(), other.size()));
size_ = other.size();
TypeOperations::UninitializedCopy(other, base::span(*this),
VectorOperationOrigin::kConstruction);
}
When other.size() exceeds 2^32 (e.g., 0x100000100 bytes), the Base (VectorBuffer) constructor receives the truncated 32-bit value (e.g., 0x100). This results in an undersized buffer allocation (e.g., 256 bytes).
Subsequently, TypeOperations::UninitializedCopy is called. For types that use memcpy (like char), it calculates the copy length based on the source span’s original 64-bit extent. This results in a memcpy of the full >4 GiB source data into the truncated 256-byte destination buffer, causing a linear heap buffer overflow.
Reachability and Impact
This vulnerability is potentially reachable from JavaScript without user interaction via the IndexedDB API. In third_party/blink/renderer/bindings/modules/v8/v8_binding_for_modules.cc, using an ArrayBuffer as an IndexedDB key triggers the vulnerable WTF::Vector<char> constructor:
return IDBKey::CreateBinary(
base::MakeRefCounted<base::RefCountedData<Vector<char>>>(
Vector<char>(base::as_chars(buffer->ByteSpan()))));
On 64-bit systems, ArrayBuffer objects can be as large as 32 GiB. An attacker can allocate an ArrayBuffer larger than 4 GiB and use it as a key in an operation like IDBObjectStore.put().
While a massive linear overflow will eventually hit a PartitionAlloc guard page (located every 2MB) and cause a crash, it can corrupt adjacent heap objects before the crash occurs. Since the destination vector is allocated on the renderer heap outside the V8 sandbox, this provides a primitive for memory corruption within the renderer process.
Suggested Potential Reproduction Steps
- On a 64-bit system with sufficient RAM, open a website and initialize an IndexedDB database.
- In JavaScript, allocate an
ArrayBufferlarger than 4 GiB (e.g.,new ArrayBuffer(0x100000100)). - Perform an IndexedDB operation using this buffer as a key:
let largeKey = new ArrayBuffer(0x100000100); db.transaction('store', 'readwrite').objectStore('store').put('value', largeKey); - The renderer is expected to crash due to a heap buffer overflow in
memcpywithin theWTF::Vectorconstructor.
Note: These steps are suggested based on code analysis; the behavior hasn’t been verified with a running PoC.
Recommended Fix
Apply base::checked_cast<wtf_size_t> to the span size in the constructor to ensure that any size exceeding the maximum wtf_size_t results in a safe crash/exception rather than a truncation.
template <typename U>
Vector<T, InlineCapacity, Allocator>::Vector(base::span<const U> other)
: Base(base::checked_cast<wtf_size_t>(other.size())) {
...
size_ = base::checked_cast<wtf_size_t>(other.size());
...
}
Evaluated with Chrome root at commit: 29093e11cf509e3593f6229e4b1b075cca356049
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.