High watch CVSS 3.1 chrome OOB 📄 Reporter bug report 🔧 Commit mapped

Overview

High
Severity
3.1
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactOut of bounds read in CrashReporting
DescriptionOut of bounds read in CrashReporting
ComponentCrashReporting
Sub-componentInternals>CrashReporting
Bug ClassOOB
Action tierwatch — information disclosure — security-relevant, below the RCE-class bar
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker502304489
Fix commitda2e30bc2075 (chromium/src) +16/-2
CWECWE-125 (Out-of-bounds read)
CVSS vectorCVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:L/I:N/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-04-13 (per vendor advisory)
Fix landed2026-08-26 (public git)
Disclosed2026-09-03
Patch gap8 days — fix public in source before the advisory

Background

Crashpad
Chromium’s crash-reporting library, bundled under third_party/crashpad; this fix rolls it to revision 60dd943f48d77dc8d05dabc04badbd8561d0b8c4.
`ProcessSnapshotSanitized` / `ScanStackForPointers`
the sanitization pass over a captured process snapshot that walks the stack memory looking for pointer-shaped values (e.g. to redact them), templated on Pointer.
`stack_pointer_` / `stack_->Address()`
the captured stack-pointer register value and the base address of the captured stack memory region; the scan computes sp_offset as their difference.
`AssignIfInRange`
a helper that stores an integer into a target only if it fits the target type’s range, returning false otherwise.

Root Cause Analysis

ScanStackForPointers computed sp_offset as stack_pointer_ - stack_->Address() and passed it straight to AssignIfInRange(&sp_offset, ...). As the added comment states, stack_pointer_ “might point below the stack region if ProcessReaderLinux interpreted it as pointing to a guard page,” so the subtraction of two unsigned addresses can underflow to a huge value. The old code’s only guard was AssignIfInRange, which merely checks that the (already-wrapped) difference fits size_t and returns false on failure — it does not detect that stack_pointer_ < stack_->Address(), so a below-region stack pointer produced a bogus enormous sp_offset that was then used (after alignment to aligned_sp_offset) to index into the stack buffer, yielding an out-of-bounds read while scanning.

The fix adds an explicit ordering check: if stack_pointer_ < stack_->Address() it sets sp_offset = 0 (treating the scan as starting at the region base), and only otherwise falls back to the AssignIfInRange path. This keeps the scan’s starting offset within the captured region and prevents the underflow-driven OOB read.

Key insight
The single mistake was subtracting two addresses without first checking their order, so a stack_pointer_ below stack_->Address() (a guard-page interpretation) underflowed into a huge sp_offset; the fix clamps that case to sp_offset = 0 before any range or indexing use.

Attack Path

  1. Produce a crash with an out-of-range stack pointer A process crashes such that its captured stack_pointer_ is interpreted by ProcessReaderLinux as pointing to a guard page below the captured stack region’s base stack_->Address().
  2. Underflowing offset ScanStackForPointers computes stack_pointer_ - stack_->Address(); because stack_pointer_ < stack_->Address(), the unsigned subtraction wraps to a very large value that AssignIfInRange does not reject as a below-region condition.
  3. Out-of-bounds stack scan The bogus sp_offset (after alignment) is used to walk the captured stack buffer, causing an out-of-bounds read during pointer scanning, consistent with the advisory’s “Out of bounds read in CrashReporting.”
  4. Downstream effect Any leakage or crash from reading past the buffer is not shown in the diff beyond the OOB read itself and is (inferred).

Impact Assessment

An attacker (or an attacker-influenced crash) that yields a captured stack pointer below the recorded stack region triggers an out-of-bounds read inside Crashpad’s sanitized snapshot scan, in whatever process performs snapshot sanitization; the precondition is a crash whose stack_pointer_ is treated as a guard-page address below stack_->Address(). The advisory reports an out-of-bounds read and does not state exploitation in the wild; escalation beyond the read (information disclosure, crash) is (inferred).

Files Changed

  • third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
  • third_party/crashpad/crashpad/util/numeric/int128_test.cc
  • third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
  • third_party/crashpad/crashpad/util/misc/reinterpret_bytes.cc
  • third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
  • third_party/crashpad/README.chromium
  • third_party/crashpad/crashpad/util/linux/pac_helper.cc
  • third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc
  • third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc
  • third_party/crashpad/crashpad/util/misc/capture_context_test_util_win.cc
  • third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
  • third_party/crashpad/crashpad/util/misc/capture_context_test_util_mac.cc

Audit Directions

  • Unsigned address subtraction
    Audit any ptr_a - ptr_b on addresses/offsets where ptr_a can legitimately be below ptr_b; unsigned underflow produces huge values that later index or size buffers.
  • Range checks that miss the low end
    Where a value is validated only with a fits-in-type or upper-bound helper (like AssignIfInRange), confirm the below-region/negative case is separately rejected before use.
  • Attacker-influenced register/state in crash capture
    Review crash-snapshot and stack-scanning code that consumes register values (stack/frame pointers) which a crashing (potentially compromised) process can control, treating them as untrusted bounds.
From da2e30bc2075402c4bd68fe1af7674bfbe3f5a4a Mon Sep 17 00:00:00 2001
From: Joshua Peraza <[email protected]>
Date: Wed, 26 Aug 2026 10:30:05 -0700
Subject: [PATCH] Update Crashpad to 60dd943f48d77dc8d05dabc04badbd8561d0b8c4

48b459d7aed3 Add missing build/build_config.h includes
60dd943f48d7 Round up OOB stack pointers in ScanStackForPointers

Bug: 502304489
Change-Id: I8d2c6a0e72a03ecb8b25d4cb5292ef743a3c0d23
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8279916
Commit-Queue: Mark Mentovai <[email protected]>
Auto-Submit: Joshua Peraza <[email protected]>
Reviewed-by: Mark Mentovai <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1686535}
---
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 8d2e2fda..a20b700 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://chromium.googlesource.com/crashpad/crashpad
 Version: N/A
-Revision: ad1827ddbc03f1c214030b31b380243ded660b95
+Revision: 60dd943f48d77dc8d05dabc04badbd8561d0b8c4
 Update Mechanism: Manual
 License: Apache-2.0
 License File: crashpad/LICENSE
diff --git a/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc b/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc
index afa1c9f..5d44229 100644
--- a/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc
+++ b/third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc
@@ -52,7 +52,11 @@
   template <typename Pointer>
   bool ScanStackForPointers(void* data, size_t size) {
     size_t sp_offset;
-    if (!AssignIfInRange(&sp_offset, stack_pointer_ - stack_->Address())) {
+    // stack_pointer_ might point below the stack region if ProcessReaderLinux
+    // interpreted it as pointing to a guard page.
+    if (stack_pointer_ < stack_->Address()) {
+      sp_offset = 0;
+    } else if (!AssignIfInRange(&sp_offset, stack_pointer_ - stack_->Address())) {
       return false;
     }
     const size_t aligned_sp_offset =
diff --git a/third_party/crashpad/crashpad/util/linux/pac_helper.cc b/third_party/crashpad/crashpad/util/linux/pac_helper.cc
index a9d5f04..49eccce2 100644
--- a/third_party/crashpad/crashpad/util/linux/pac_helper.cc
+++ b/third_party/crashpad/crashpad/util/linux/pac_helper.cc
@@ -24,6 +24,7 @@
   #include <ptrauth.h>
 #endif
 
+#include "build/build_config.h"
 #include "util/misc/address_types.h"
 
 namespace crashpad {
diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc
index 55820b9..9b357ada 100644
--- a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc
+++ b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc
@@ -14,6 +14,7 @@
 
 #include "util/misc/capture_context_test_util.h"
 
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "util/misc/from_pointer_cast.h"
 
diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_mac.cc b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_mac.cc
index 8a75b03..841aec4 100644
--- a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_mac.cc
+++ b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_mac.cc
@@ -14,6 +14,7 @@
 
 #include "util/misc/capture_context_test_util.h"
 
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "util/misc/implicit_cast.h"
 
diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_win.cc b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_win.cc
index e21d865..70a6a7d 100644
--- a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_win.cc
+++ b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_win.cc
@@ -16,6 +16,7 @@
 
 #include <iterator>
 
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "util/win/context_wrappers.h"
 
diff --git a/third_party/crashpad/crashpad/util/misc/reinterpret_bytes.cc b/third_party/crashpad/crashpad/util/misc/reinterpret_bytes.cc
index 5909b728..e7e5809b 100644
--- a/third_party/crashpad/crashpad/util/misc/reinterpret_bytes.cc
+++ b/third_party/crashpad/crashpad/util/misc/reinterpret_bytes.cc
@@ -19,6 +19,7 @@
 #include <algorithm>
 
 #include "base/logging.h"
+#include "build/build_config.h"
 
 namespace crashpad {
 namespace internal {
diff --git a/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc b/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
index af245d3..dbdcb8b 100644
--- a/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
@@ -22,6 +22,7 @@
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h"
 #include "test/multiprocess_exec.h"
diff --git a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
index 1862488..a17b4c4 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
@@ -25,6 +25,7 @@
 
 #include "base/bit_cast.h"
 #include "base/strings/stringprintf.h"
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "snapshot/cpu_architecture.h"
 #include "snapshot/linux/process_reader_linux.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
index caacc19..06589d99 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
@@ -16,6 +16,7 @@
 
 #include <mach/mach.h>
 
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 
 namespace crashpad {
diff --git a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
index aa78e55..efb3bf8 100644
--- a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
@@ -20,6 +20,7 @@
 
 #include "base/files/file_path.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "snapshot/win/exception_snapshot_win.h"
 #include "snapshot/win/process_snapshot_win.h"
diff --git a/third_party/crashpad/crashpad/util/numeric/int128_test.cc b/third_party/crashpad/crashpad/util/numeric/int128_test.cc
index 5bc9e41..43eaf08 100644
--- a/third_party/crashpad/crashpad/util/numeric/int128_test.cc
+++ b/third_party/crashpad/crashpad/util/numeric/int128_test.cc
@@ -15,6 +15,7 @@
 #include "util/numeric/int128.h"
 
 #include "base/bit_cast.h"
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 
 namespace crashpad {
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc b/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
index af245d3..dbdcb8b 100644
--- a/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/fuchsia/process_snapshot_fuchsia_test.cc
@@ -22,6 +22,7 @@
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "snapshot/fuchsia/memory_map_region_snapshot_fuchsia.h"
 #include "test/multiprocess_exec.h"
diff --git a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
index 1862488..a17b4c4 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
@@ -25,6 +25,7 @@
 
 #include "base/bit_cast.h"
 #include "base/strings/stringprintf.h"
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "snapshot/cpu_architecture.h"
 #include "snapshot/linux/process_reader_linux.h"
diff --git a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
index caacc19..06589d99 100644
--- a/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/mac/cpu_context_mac_test.cc
@@ -16,6 +16,7 @@
 
 #include <mach/mach.h>
 
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 
 namespace crashpad {
diff --git a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
index aa78e55..efb3bf8 100644
--- a/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/exception_snapshot_win_test.cc
@@ -20,6 +20,7 @@
 
 #include "base/files/file_path.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 #include "snapshot/win/exception_snapshot_win.h"
 #include "snapshot/win/process_snapshot_win.h"
diff --git a/third_party/crashpad/crashpad/util/numeric/int128_test.cc b/third_party/crashpad/crashpad/util/numeric/int128_test.cc
index 5bc9e41..43eaf08 100644
--- a/third_party/crashpad/crashpad/util/numeric/int128_test.cc
+++ b/third_party/crashpad/crashpad/util/numeric/int128_test.cc
@@ -15,6 +15,7 @@
 #include "util/numeric/int128.h"
 
 #include "base/bit_cast.h"
+#include "build/build_config.h"
 #include "gtest/gtest.h"
 
 namespace crashpad {
Loading diff…

Original Bug Report

reported by [email protected]

Potential Heap OOB Read in crashpad_handler due to Integer Underflow in ScanStackForPointers

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 without the Chrome Security team.

Overview: An integer underflow vulnerability exists in Crashpad’s ScanStackForPointers when calculating the offset between an attacker-supplied stack pointer and the resolved stack base address. By supplying a crafted ucontext_t and memory layout, a compromised sandboxed process can trick the privileged crashpad_handler into performing an out-of-bounds heap read. This can be leveraged as a timing oracle to leak heap contents and bypass ASLR in the handler process.

Affected files:

  • third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc

Estimated timestamp from git blame: 2023-04-10

Root Cause

A potential integer underflow exists in third_party/crashpad/crashpad/snapshot/sanitized/process_snapshot_sanitized.cc within the ScanStackForPointers template function:

template <typename Pointer>
bool ScanStackForPointers(void* data, size_t size) {
  size_t sp_offset;
  if (!AssignIfInRange(&sp_offset, stack_pointer_ - stack_->Address())) {
    return false;
  }
  const size_t aligned_sp_offset =
      (sp_offset + sizeof(Pointer) - 1) & ~(sizeof(Pointer) - 1);

  auto words = reinterpret_cast<Pointer*>(static_cast<char*>(data) +
                                          aligned_sp_offset);
  size_t word_count = (size - aligned_sp_offset) / sizeof(Pointer);
  for (size_t index = 0; index < word_count; ++index) {
    auto word = StripPACBits(words[index]);
    if (word >= low_ && word < high_) {
      return true;
    }
  }
  return false;
}

If a client provides a stack_pointer_ that is strictly less than stack_->Address(), the subtraction stack_pointer_ - stack_->Address() underflows. Since VMAddress is uint64_t and size_t is a 64-bit unsigned integer on 64-bit systems, the underflowed value remains perfectly within the range of size_t. Consequently, AssignIfInRange returns true, assigning a massive positive value (e.g., 0xFFFFFFFFFFFFE000) to sp_offset.

When aligned_sp_offset is added to data, standard 64-bit pointer arithmetic wraps around, causing the words pointer to point to memory before the heap-allocated data buffer. Simultaneously, size - aligned_sp_offset also underflows. Because of integer modular arithmetic, this calculates the exact number of words required to scan from the out-of-bounds pointer up to the end of the legitimate data buffer.

Potential Exploitation Steps

(Note: These are theoretical/suggested steps, as our AI tooling does not currently have the ability to run a live proof of concept.)

  1. Setup: An attacker gains arbitrary code execution in a sandboxed client process.
  2. Memory Grooming (Client): The attacker maps a valid stack region (e.g., at 0x40000000) and an unreadable guard page immediately below it (e.g., at 0x3FFFF000).
  3. Fake Module: The attacker creates a fake ELF module in their memory space by manipulating the dynamic linker’s link_map. They use PT_LOAD segments to arbitrarily define the [low_, high_) bounds they wish to scan for in the handler’s heap.
  4. Fake Context: The attacker constructs a fake ucontext_t struct, setting the stack pointer (rsp/sp) to 0x3FFFF000 (inside the guard page) and the instruction pointer to a value outside the fake module.
  5. Trigger: The attacker triggers a crash dump request via IPC to crashpad_handler, passing pointers to the fake ucontext_t and a SanitizationInformation struct pointing to their fake module.
  6. Handler Processing: crashpad_handler reads the attacker’s context. When finding the stack mapping for 0x3FFFF000, ProcessReaderLinux detects the guard page and safely bumps stack_->Address() to the start of the valid mapping at 0x40000000.
  7. Underflow: In ScanStackForPointers, stack_pointer_ (0x3FFFF000) minus stack_->Address() (0x40000000) underflows to -0x1000 (represented as a huge unsigned integer).
  8. OOB Read: words points to data - 0x1000. The loop reads out-of-bounds heap memory before the allocated stack buffer.
  9. Timing Oracle: If a value in the OOB memory falls within the attacker’s [low_, high_) range, the function returns true, leading to full, slow minidump generation (involving heavy I/O). If no match is found, sanitization fails and the handler exits almost instantly. The attacker observes this massive timing difference to perform a binary search and leak heap contents, bypassing ASLR for the privileged crashpad_handler process.

Suggested Fix

Add bounds checking before the pointer arithmetic in ScanStackForPointers:

  if (stack_pointer_ < stack_->Address()) {
    return false;
  }
  size_t sp_offset;
  // ... existing AssignIfInRange check ...
  
  const size_t aligned_sp_offset =
      (sp_offset + sizeof(Pointer) - 1) & ~(sizeof(Pointer) - 1);
      
  if (aligned_sp_offset > size) {
    return false;
  }

This ensures that the stack pointer resides within the bounds of the resolved stack region, completely eliminating the underflow and subsequent OOB read.

Evaluated with Chrome root at commit: 096fc8fdbfacf2546485756d03f160a3d04fcc9b


Results 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.

View on issue tracker