Overview

Medium
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactOut of bounds read in V8
DescriptionOut of bounds read in V8
ComponentV8
Bug ClassOOB
Tracker513435594
Fix commit6d33b8b329ef (v8/v8) +10/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-06-30

Changed Functions

FunctionChangeNotes
if
src/profiler/profile-generator.cc
modified

Files Changed

  • src/profiler/profile-generator.cc
From 6d33b8b329ef903dde6a296ebd973a41ea298de6 Mon Sep 17 00:00:00 2001
From: Benedikt Meurer <bmeurer@chromium.org>
Date: Fri, 15 May 2026 13:06:18 +0200
Subject: [PATCH] [profiler] Prevent data race on `CodeEntry::rare_data_`.

This adds an explicit memory barrier to `CodeEntry::EnsureRareData()`
for platforms with store-store reordering (e.g. arm64), where it's
otherwise possible to that the store to `rare_data_` becomes visible to
other threads before the field initialization completes.

Fixed: 513435594
Change-Id: I78a45c35bed6a3a2459c1ec994393709027c5f22
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7849376
Reviewed-by: Yang Guo <yangguo@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
Auto-Submit: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/main@{#107368}
---

diff --git a/src/profiler/profile-generator.cc b/src/profiler/profile-generator.cc
index b62c067..bb7aea1 100644
--- a/src/profiler/profile-generator.cc
+++ b/src/profiler/profile-generator.cc
@@ -5,6 +5,7 @@
 #include "src/profiler/profile-generator.h"
 
 #include <algorithm>
+#include <atomic>
 #include <vector>
 
 #include "include/v8-profiler.h"
@@ -270,7 +271,15 @@
 
 CodeEntry::RareData* CodeEntry::EnsureRareData() {
   if (!rare_data_) {
-    rare_data_.reset(new RareData());
+    // On platforms with store-store reordering, we need to ensure that the
+    // field initializations in RareData complete before the pointer (in the
+    // std::unique_ptr) becomes visible. Using an std::atomic for rare_data_
+    // would also work, but would penalize every read, also on platforms with
+    // no store-store reordering (like x64).
+    // See http://crbug.com/513435594 for additional details.
+    RareData* rare_data = new RareData();
+    std::atomic_thread_fence(std::memory_order_release);
+    rare_data_.reset(rare_data);
   }
   return rare_data_.get();
 }
Loading diff…

Original Bug Report

reported by vm...@google.com

Potential data race in V8 CPU Profiler allows arbitrary memory read via CDP

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 data race in V8’s CPU profiler occurs when CodeEntry::rare_data_ is accessed concurrently by the profiler and main threads without synchronization. On weakly-ordered architectures like ARM64, this can lead to an arbitrary native memory read primitive accessible via the Chrome DevTools Protocol (CDP).

Affected files:

  • v8/src/profiler/profile-generator.h
  • v8/src/profiler/profile-generator.cc
  • v8/src/profiler/cpu-profiler.cc
  • v8/src/inspector/v8-profiler-agent-impl.cc
  • v8/src/api/api.cc
  • v8/src/profiler/cpu-profiler-inl.h

Estimated timestamp from git blame: 2018-05-18

Summary

A potential data race in the V8 CPU profiler allows for a wild pointer read, which could be exploited to leak renderer process memory via the Chrome DevTools Protocol (CDP). The issue stems from unsynchronized access to CodeEntry::rare_data_ when a profile is being serialized on the main thread while the profiler background thread is concurrently updating deoptimization or bailout metadata.

Technical Details

The CodeEntry class (defined in v8/src/profiler/profile-generator.h) uses a std::unique_ptr<RareData> rare_data_ to store optional metadata such as bailout reasons and deoptimization information. This pointer is accessed across threads without atomic protections or mutexes.

  1. Concurrent Writer: The SamplingEventsProcessor thread processes code events (e.g., CodeDisableOptEvent). It calls CodeEntry::set_bailout_reason(), which invokes EnsureRareData(). This method allocates a new RareData object and assigns it to the rare_data_ unique pointer:

    CodeEntry::RareData* CodeEntry::EnsureRareData() {
      if (!rare_data_) {
        rare_data_.reset(new RareData());
      }
      return rare_data_.get();
    }
    
  2. Concurrent Reader: When multiple profiling sessions are active on a single v8::CpuProfiler, calling StopProfiling on one session does not stop the background profiler thread if other sessions remain active. While the background thread continues processing events, the main thread begins serializing the stopped profile. This eventually calls CodeEntry::bailout_reason() via the V8 API (v8::CpuProfileNode::GetBailoutReason):

    const char* bailout_reason() const {
      return rare_data_ ? rare_data_->bailout_reason_ : kEmptyBailoutReason;
    }
    
  3. The Race: On weakly-ordered architectures (such as ARM64), the memory store to rare_data_ and the initialization of its fields (like bailout_reason_) can be reordered. Consequently, the main thread may observe a non-null rare_data_ pointer before its internal bailout_reason_ pointer has been correctly initialized. If the underlying memory was previously controlled by an attacker (e.g., via heap spraying), the reader may dereference a stale or malicious pointer.

Potential Impact

An attacker with access to the Profiler CDP domain (e.g., via a chrome.debugger extension or a compromised renderer) could potentially perform an arbitrary-address null-terminated read of the renderer process memory. The leaked data is returned to the CDP client as a string in the consoleProfileFinished event or the Profiler.stop response. This could be used to leak sensitive information or bypass ASLR.

Suggested Potential Exploitation Steps

  1. Attach a CDP client to the target renderer.
  2. Spray the native heap with objects of the same size as RareData containing a target memory address at the offset of bailout_reason_.
  3. Start multiple concurrent CPU profiling sessions.
  4. Trigger a code event that causes an optimization bailout (e.g., executing code that violates a previous optimization assumption).
  5. Immediately stop one of the profiling sessions.
  6. The race condition may cause the serialization process to read the attacker-controlled pointer as a const char*, leaking memory from that address into the CDP response.

Suggested Fix

Access to CodeEntry::rare_data_ should be synchronized. This can be achieved by making rare_data_ an std::atomic<RareData*> with proper memory ordering (Acquire/Release) or by protecting the CodeEntry metadata with a mutex. Given that CodeEntry objects are heavily used during profiling, a lock-free approach with atomics is likely preferable for performance.

Evaluated with Chrome root at commit: b3153093eb3c78c3e88ccf562bcbc20437a04b0e


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.

View on issue tracker