Medium chrome Memory Corruption 📄 Reporter bug report 🔧 Commit mapped

Overview

Medium
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMemory corruption in DevTools
DescriptionMemory corruption in DevTools
ComponentDevTools
Sub-componentPlatform>DevTools
Bug ClassMemory Corruption
Tracker553114456
Fix commit611969dd519b (chromium/src) +1/-1
CISA KEVNot listed
CreditedGoogle
Disclosed2026-10-20

Files Changed

  • content/browser/devtools/devtools_session.cc
From 611969dd519b88ca3cdce3c76dbb1668e67b5a3f Mon Sep 17 00:00:00 2001
From: Alex Rudenko <[email protected]>
Date: Wed, 16 Sep 2026 01:10:02 -0700
Subject: [PATCH] Forward validated message_span to the client

Forward the validated data copy instead of the original message->data.

Fixed: 553114456
Change-Id: I00017b108c4c7a12a10149b83b554eb95088d735
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8409087
Commit-Queue: Alex Rudenko <[email protected]>
Reviewed-by: Danil Somsikov <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1698719}
---
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index 54d3440..588f777 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -603,7 +603,7 @@
     }
     return;
   }
-  client->DispatchProtocolMessage(agent_host, message->data);
+  client->DispatchProtocolMessage(agent_host, message_span);
 }
 
 void DevToolsSession::DispatchProtocolResponse(
Loading diff…

Original Bug Report

reported by [email protected]

BigBuffer TOCTOU in DevToolsSession::DispatchProtocolResponseOrNotification

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: DevToolsSession::DispatchProtocolResponseOrNotification makes a temporary copy of a shared-memory BigBuffer solely to perform message validation, but then forwards the original shared-memory buffer to the client. Because the sending renderer process retains a writable mapping to the shared memory region, a compromised renderer could rewrite message contents after validation succeeds but before the client processes them. This allows an attacker to bypass DevToolsMessage validation checks and spoof or forge protocol messages across DevTools sessions.

Affected files:

  • content/browser/devtools/devtools_session.cc

Estimated timestamp from git blame: 2026-06-15

Potential BigBuffer TOCTOU in DevToolsSession::DispatchProtocolResponseOrNotification

Location

content/browser/devtools/devtools_session.cc:576-607

Summary

In DevToolsSession::DispatchProtocolResponseOrNotification, messages backed by shared memory (mojo_base::BigBuffer::StorageType::kSharedMemory) are copied into a local std::vector<uint8_t> to validate them against spoofing attacks (e.g., verifying sessionId matches the child target). However, after ValidateMessage passes, the function passes the original message->data instead of the validated copy to client->DispatchProtocolMessage.

Because the sending (compromised) renderer retains writable access to the shared memory region backing the BigBuffer, it can modify the message contents in shared memory concurrently while or after validation runs, leading to a Time-of-Check to Time-of-Use (TOCTOU) validation bypass.

Detailed Analysis

In content/browser/devtools/devtools_session.cc:576-607:

void DevToolsSession::DispatchProtocolResponseOrNotification(
    DevToolsAgentHostClient* client,
    DevToolsAgentHostImpl* agent_host,
    blink::mojom::DevToolsMessagePtr message,
    const std::string& session_id,
    const bool& is_notification) {
  // If BigBuffer is backed by shared memory, make a copy so that a compromised
  // renderer wouldn't be able to mess with the message as we validate it.
  std::vector<uint8_t> message_bytes;
  base::span<const uint8_t> message_span;
  switch (message->data.storage_type()) {
    case mojo_base::BigBuffer::StorageType::kBytes:
      message_span = message->data.byte_span();
      break;
    case mojo_base::BigBuffer::StorageType::kSharedMemory:
      message_bytes.assign(message->data.begin(), message->data.end());
      message_span = message_bytes;
      break;
    default:
      break;
  }

  const bool message_is_valid =
      !message_span.empty() &&
      ValidateMessage(session_id,
                      /*expected_has_id=*/!is_notification, message_span,
                      /*expect_cbor */ client->UsesBinaryProtocol());
  if (!message_is_valid) {
    if (RenderProcessHost* process_host = agent_host->GetProcessHost()) {
      bad_message::ReceivedBadMessage(
          process_host, bad_message::RFH_INCONSISTENT_DEVTOOLS_MESSAGE);
    }
    return;
  }
  client->DispatchProtocolMessage(agent_host, message->data);
}
  1. At line 585, message_bytes creates a heap copy of the shared-memory-backed message->data.
  2. At line 596, ValidateMessage is executed on message_span (referencing message_bytes), ensuring the message does not illegally forge sessionId or id attributes.
  3. At line 606, client->DispatchProtocolMessage(agent_host, message->data) passes message->data (implicitly converted to base::span<const uint8_t>), which points to the live mapping (BigBuffer::data() in mojo/public/cpp/base/big_buffer.cc:116-118).
  4. As documented in mojo/public/cpp/base/big_buffer.h:74-78, Mojo shared memory regions may remain writable in the sender process. The sender can alter memory in the shared region before the client (such as TargetHandler::Session, DevToolsUIBindings, or DevToolsPipeHandler) copies or processes the span.
  5. Downstream consumers do not perform any secondary validation on the message.

Potential Trigger Steps

(Note: These are suggested potential steps derived from static code analysis; automated dynamic proof of concept execution has not been run.)

  1. A compromised renderer with an active DevTools session creates a shared-memory backed BigBuffer for blink.mojom.DevToolsMessage.
  2. The renderer retains a writable mapping to the shared memory region on a secondary thread.
  3. The renderer constructs a valid DevTools protocol message containing its assigned sessionId and a large payload (to widen the processing window in ValidateMessage).
  4. The renderer calls DevToolsSessionHost::DispatchProtocolNotification or DispatchProtocolResponse.
  5. In the race window while ValidateMessage evaluates the snapshot, the background thread in the renderer rewrites the shared memory buffer to strip sessionId, alter sessionId to another target, or inject response fields.
  6. ValidateMessage succeeds based on the snapshot, and line 606 dispatches the tampered live shared buffer to the client, which accepts and routes the forged message.

Impact

A compromised renderer process (e.g. an out-of-process iframe) could forge protocol events or responses directed to the root target session (sessionId = '') or other target frames in flattened DevTools debugging mode, bypassing Site Isolation boundaries within the DevTools frontend and client tooling.

Suggested Fix

Ensure that the validated data (message_span / message_bytes) is dispatched to the client rather than the renderer-writable original buffer. For example:

  if (message->data.storage_type() == mojo_base::BigBuffer::StorageType::kSharedMemory) {
    client->DispatchProtocolMessage(agent_host, message_span);
  } else {
    client->DispatchProtocolMessage(agent_host, message->data);
  }

Alternatively, replace message->data with mojo_base::BigBuffer(message_bytes) or pass message_span unconditionally to client->DispatchProtocolMessage.

Evaluated with Chrome root at commit: c6718ebbf2c677c6f63691e28c7801c563f6b19c


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