Overview

Critical
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in Chromoting
DescriptionUse after free in Chromoting
ComponentChromoting
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.
Tracker522819252
Fix commit02bd649092f6 (chromium/src) +115/-12
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
CreditedGoogle
Reported2026-06-11 (per vendor advisory)
Fix landed2026-08-14 (public git)
Disclosed2026-08-20
Patch gap6 days — fix public in source before the advisory

Background

Chromoting / remoting host
Chrome’s Remote Desktop host code (remoting/) that authenticates and serves an incoming remote client over a Jingle-based protocol.
`NegotiatingHostAuthenticator`
the host-side authenticator that picks a concrete auth method (SPAKE2 shared-secret, paired, or SessionAuthz) and drives the challenge/response state machine for a session.
`resume_callback` (`base::OnceClosure`)
a continuation passed into a sub-authenticator’s Start/Initialize; when the method setup can complete or fail immediately it may be run synchronously, before control returns to the caller.
`WeakPtr` self-guard
the Chromium idiom of taking weak_factory_.GetWeakPtr() before invoking a callback that may destroy this, then checking the pointer afterward to detect self-destruction and bail out.

Root Cause Analysis

In NegotiatingHostAuthenticator::CreateAuthenticator (named in the commit subject; the @@ hunk header only shows the base::OnceClosure resume_callback) parameter line, not the enclosing function), the code created a concrete authenticator and invoked its Start/Initialize with std::move(resume_callback), then, after the switch, dereferenced the member current_authenticator_ via ChainStateChangeAfterAcceptedWithUnderlying(*current_authenticator_). The violated invariant is that this must still be alive when that trailing member access runs: because resume_callback can execute synchronously inside Start/Initialize, it can drive the session to closure and destroy the NegotiatingHostAuthenticator instance before the callback returns, leaving the subsequent *current_authenticator_ access reading freed memory (a use-after-free).

The fix captures auto weak_this = weak_factory_.GetWeakPtr(); at function entry and inserts if (!weak_this) { return; } immediately before the ChainStateChangeAfterAcceptedWithUnderlying(*current_authenticator_) call, so a self-destroying callback causes an early return instead of a dangling dereference. As a companion correctness change, each branch now assigns current_authenticator_ = std::move(authenticator) before calling Start/Initialize through a saved raw pointer (auth_ptr), so ownership is settled before the callback can run rather than being written back into a member of an already-freed object.

Key insight
The single mistake is invoking a caller-supplied continuation (resume_callback) that can synchronously destroy this, then unconditionally touching the member current_authenticator_ afterward; the fix detects that self-destruction with a pre-captured weak_this and returns early before the member is dereferenced.

Attack Path

  1. Initiate a host authentication A remote client connects to a Chromoting host and sends a JingleAuthentication message selecting an offered method (e.g. SHARED_SECRET_SPAKE2_CURVE25519, PAIRED_SPAKE2_CURVE25519, or CLOUD_SESSION_AUTHZ_SPAKE2_CURVE25519), driving the host into NegotiatingHostAuthenticator::CreateAuthenticator.
  2. Force a synchronous continuation Setup for the chosen method completes or fails immediately, so resume_callback runs synchronously inside Start/Initialize; the shipped SessionAuthz regression test models this with GenerateHostToken returning PERMISSION_DENIED synchronously, and the shared-secret/pairing tests do it via a SynchronousPairingRegistry.
  3. Trigger session teardown from the callback The synchronous resume_callback drives the session to closure, which destroys the NegotiatingHostAuthenticator (this) — the regression tests reproduce this precisely with a callback of [&]() { host.reset(); }.
  4. Dereference freed memory Control returns from Start/Initialize into CreateAuthenticator, which (pre-patch) executes ChainStateChangeAfterAcceptedWithUnderlying(*current_authenticator_), reading current_authenticator_ out of the now-freed this — the use-after-free.
  5. Downstream escalation Any read/write primitive, controlled reallocation of the freed region, or code execution arising from the freed access is not shown by the diff and is (inferred).

Impact Assessment

An attacker able to reach and drive the host authentication handshake can cause a use-after-free in the Chromoting host process during session setup, when a method’s resume_callback runs synchronously and tears down the NegotiatingHostAuthenticator before the trailing current_authenticator_ dereference. The advisory classifies this as a use-after-free in Chromoting and states no more; it does not report exploited-in-the-wild status, and any progression from the freed-memory access to information disclosure, memory corruption, or code execution is (inferred) rather than demonstrated by the patch. The precondition is that setup for the negotiated method resolves synchronously and closes the session in the same call stack, as exercised by the three shipped SynchronousTeardown tests.

Changed Functions

FunctionChangeNotes
switch
remoting/protocol/negotiating_host_authenticator.cc
modified
if
remoting/protocol/negotiating_host_authenticator.cc
modified
FakeSessionAuthzServiceClientFactory
remoting/protocol/negotiating_authenticator_unittest.cc
modified
NegotiatingAuthenticatorTest
remoting/protocol/negotiating_authenticator_unittest.cc
modified
BindLambdaForTesting
remoting/protocol/negotiating_authenticator_unittest.cc
modified

Files Changed

  • remoting/protocol/negotiating_host_authenticator.cc
  • remoting/protocol/negotiating_authenticator_unittest.cc

Audit Directions

  • Callback-then-member-access
    Audit any method that invokes a base::OnceClosure/base::RepeatingCallback (especially resume/continue callbacks) and then touches this members or calls member functions afterward; require a WeakPtr self-guard whenever the callback can synchronously destroy the object.
  • Synchronous-completion paths
    Look for authenticators, registries, and service clients (e.g. SessionAuthzServiceClient, PairingRegistry) whose Start/Initialize/Generate* operations may invoke their completion callback inline rather than posting it, since these turn “later” teardown into same-stack destruction.
  • Assign-after-use ordering
    Flag places that move a locally-owned object into a member after invoking a callback on it, where the member write could land in freed storage; prefer assigning ownership first and calling through a saved raw pointer, as this fix does.
From 02bd649092f62e8416f02eca484578c20e88ba7d Mon Sep 17 00:00:00 2001
From: Joe Downing <[email protected]>
Date: Fri, 14 Aug 2026 10:28:51 -0700
Subject: [PATCH] Fix potential UAF in NegotiatingHostAuthenticator::CreateAuthenticator

During authentication setup, synchronous execution of resume_callback in NegotiatingHostAuthenticator::CreateAuthenticator can result in session closure and destruction of the NegotiatingHostAuthenticator instance. Upon returning from the callback, accessing current_authenticator_ causes a Use-After-Free.

This CL captures a WeakPtr before invoking the callback and returns early if this was destroyed.

TAG=agy
CONV=ec6a5028-dd53-4091-8c6b-7a88a373cc3a

Bug: 522819252
Change-Id: I9aa68827d17dfbf6a0a9ae972c9bb8e3acbe0b11
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8261393
Commit-Queue: Joe Downing <[email protected]>
Reviewed-by: Jamie Walch <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1679658}
---
diff --git a/remoting/protocol/negotiating_host_authenticator.cc b/remoting/protocol/negotiating_host_authenticator.cc
index 69dbe5a..0d461033 100644
--- a/remoting/protocol/negotiating_host_authenticator.cc
+++ b/remoting/protocol/negotiating_host_authenticator.cc
@@ -134,6 +134,8 @@
     base::OnceClosure resume_callback) {
   DCHECK(current_method_ != AuthenticationMethod::INVALID);
 
+  auto weak_this = weak_factory_.GetWeakPtr();
+
   switch (current_method_) {
     case AuthenticationMethod::INVALID:
       NOTREACHED();
@@ -147,8 +149,9 @@
           base::BindRepeating(&Spake2Authenticator::CreateForHost, local_id_,
                               remote_id_, config_->local_cert,
                               config_->key_pair));
-      authenticator->Start(std::move(resume_callback));
+      SessionAuthzAuthenticator* auth_ptr = authenticator.get();
       current_authenticator_ = std::move(authenticator);
+      auth_ptr->Start(std::move(resume_callback));
       break;
     }
 
@@ -161,22 +164,23 @@
           base::BindRepeating(&Spake2Authenticator::CreateForHost, local_id_,
                               remote_id_, config_->local_cert,
                               config_->key_pair));
-      authenticator->Start(std::move(resume_callback));
+      SessionAuthzAuthenticator* auth_ptr = authenticator.get();
       current_authenticator_ = std::move(authenticator);
+      auth_ptr->Start(std::move(resume_callback));
       break;
     }
 
     case AuthenticationMethod::PAIRED_SPAKE2_CURVE25519: {
-      PairingHostAuthenticator* pairing_authenticator =
-          new PairingHostAuthenticator(
-              config_->pairing_registry,
-              base::BindRepeating(&Spake2Authenticator::CreateForHost,
-                                  local_id_, remote_id_, config_->local_cert,
-                                  config_->key_pair),
-              config_->shared_secret_hash);
-      current_authenticator_.reset(pairing_authenticator);
-      pairing_authenticator->Initialize(client_id_, preferred_initial_state,
-                                        std::move(resume_callback));
+      auto pairing_authenticator = std::make_unique<PairingHostAuthenticator>(
+          config_->pairing_registry,
+          base::BindRepeating(&Spake2Authenticator::CreateForHost, local_id_,
+                              remote_id_, config_->local_cert,
+                              config_->key_pair),
+          config_->shared_secret_hash);
+      PairingHostAuthenticator* auth_ptr = pairing_authenticator.get();
+      current_authenticator_ = std::move(pairing_authenticator);
+      auth_ptr->Initialize(client_id_, preferred_initial_state,
+                           std::move(resume_callback));
       break;
     }
 
@@ -188,6 +192,10 @@
       break;
   }
 
+  if (!weak_this) {
+    return;
+  }
+
   ChainStateChangeAfterAcceptedWithUnderlying(*current_authenticator_);
 }
 
diff --git a/remoting/protocol/negotiating_authenticator_unittest.cc b/remoting/protocol/negotiating_authenticator_unittest.cc
index 47e2313..f7f62c2 100644
--- a/remoting/protocol/negotiating_authenticator_unittest.cc
+++ b/remoting/protocol/negotiating_authenticator_unittest.cc
@@ -9,9 +9,12 @@
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
+#include "base/test/bind.h"
 #include "base/test/mock_callback.h"
 #include "net/base/net_errors.h"
+#include "remoting/base/mock_session_authz_service_client.h"
 #include "remoting/base/rsa_key_pair.h"
+#include "remoting/base/session_authz_service_client_factory.h"
 #include "remoting/protocol/auth_util.h"
 #include "remoting/protocol/authenticator.h"
 #include "remoting/protocol/authenticator_test_base.h"
@@ -104,6 +107,28 @@
   raw_ptr<Authenticator> authenticator_;
 };
 
+class FakeSessionAuthzServiceClientFactory
+    : public SessionAuthzServiceClientFactory {
+ public:
+  FakeSessionAuthzServiceClientFactory(
+      AuthenticationMethod method,
+      std::unique_ptr<SessionAuthzServiceClient> client)
+      : method_(method), client_(std::move(client)) {}
+
+  std::unique_ptr<SessionAuthzServiceClient> Create() override {
+    return std::move(client_);
+  }
+
+  AuthenticationMethod method() override { return method_; }
+
+ protected:
+  ~FakeSessionAuthzServiceClientFactory() override = default;
+
+ private:
+  AuthenticationMethod method_;
+  std::unique_ptr<SessionAuthzServiceClient> client_;
+};
+
 }  // namespace
 
 class NegotiatingAuthenticatorTest : public AuthenticatorTestBase {
@@ -467,4 +492,74 @@
   EXPECT_EQ(client, nullptr);
 }
 
+TEST_F(NegotiatingAuthenticatorTest,
+       CreateHostAuthenticator_SharedSecret_SynchronousTeardown) {
+  auto auth_config =
+      std::make_unique<HostAuthenticationConfig>(host_cert_, key_pair_);
+  auth_config->AddSharedSecretAuth("hash");
+  auto host = std::make_unique<NegotiatingHostAuthenticator>(
+      kHostJid, kClientJid, std::move(auth_config));
+
+  JingleAuthentication client_message;
+  client_message.method = AuthenticationMethod::SHARED_SECRET_SPAKE2_CURVE25519;
+
+  // This should not crash.
+  host->ProcessMessage(client_message,
+                       base::BindLambdaForTesting([&]() { host.reset(); }));
+
+  EXPECT_EQ(host, nullptr);
+}
+
+TEST_F(NegotiatingAuthenticatorTest,
+       CreateHostAuthenticator_Pairing_SynchronousTeardown) {
+  auto pairing_registry = base::MakeRefCounted<SynchronousPairingRegistry>(
+      std::make_unique<MockPairingRegistryDelegate>());
+  auto auth_config =
+      std::make_unique<HostAuthenticationConfig>(host_cert_, key_pair_);
+  auth_config->AddPairingAuth(pairing_registry);
+  auth_config->AddSharedSecretAuth("hash");
+  auto host = std::make_unique<NegotiatingHostAuthenticator>(
+      kHostJid, kClientJid, std::move(auth_config));
+
+  JingleAuthentication client_message;
+  client_message.method = AuthenticationMethod::PAIRED_SPAKE2_CURVE25519;
+
+  // This should not crash.
+  host->ProcessMessage(client_message,
+                       base::BindLambdaForTesting([&]() { host.reset(); }));
+
+  EXPECT_EQ(host, nullptr);
+}
+
+TEST_F(NegotiatingAuthenticatorTest,
+       CreateHostAuthenticator_SessionAuthz_SynchronousTeardown) {
+  auto mock_client = std::make_unique<MockSessionAuthzServiceClient>();
+  EXPECT_CALL(*mock_client, GenerateHostToken(_))
+      .WillOnce([](MockSessionAuthzServiceClient::GenerateHostTokenCallback
+                       callback) {
+        std::move(callback).Run(
+            HttpStatus(HttpStatus::Code::PERMISSION_DENIED, "denied"), nullptr);
+      });
+
+  auto factory = base::MakeRefCounted<FakeSessionAuthzServiceClientFactory>(
+      AuthenticationMethod::CLOUD_SESSION_AUTHZ_SPAKE2_CURVE25519,
+      std::move(mock_client));
+
+  auto auth_config =
+      std::make_unique<HostAuthenticationConfig>(host_cert_, key_pair_);
+  auth_config->AddSessionAuthzAuth(factory);
+  auto host = std::make_unique<NegotiatingHostAuthenticator>(
+      kHostJid, kClientJid, std::move(auth_config));
+
+  JingleAuthentication client_message;
+  client_message.method =
+      AuthenticationMethod::CLOUD_SESSION_AUTHZ_SPAKE2_CURVE25519;
+
+  // This should not crash.
+  host->ProcessMessage(client_message,
+                       base::BindLambdaForTesting([&]() { host.reset(); }));
+
+  EXPECT_EQ(host, nullptr);
+}
+
 }  // namespace remoting::protocol
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/remoting/protocol/negotiating_authenticator_unittest.cc b/remoting/protocol/negotiating_authenticator_unittest.cc
index 47e2313..f7f62c2 100644
--- a/remoting/protocol/negotiating_authenticator_unittest.cc
+++ b/remoting/protocol/negotiating_authenticator_unittest.cc
@@ -9,9 +9,12 @@
 #include "base/functional/bind.h"
 #include "base/memory/raw_ptr.h"
 #include "base/run_loop.h"
+#include "base/test/bind.h"
 #include "base/test/mock_callback.h"
 #include "net/base/net_errors.h"
+#include "remoting/base/mock_session_authz_service_client.h"
 #include "remoting/base/rsa_key_pair.h"
+#include "remoting/base/session_authz_service_client_factory.h"
 #include "remoting/protocol/auth_util.h"
 #include "remoting/protocol/authenticator.h"
 #include "remoting/protocol/authenticator_test_base.h"
@@ -104,6 +107,28 @@
   raw_ptr<Authenticator> authenticator_;
 };
 
+class FakeSessionAuthzServiceClientFactory
+    : public SessionAuthzServiceClientFactory {
+ public:
+  FakeSessionAuthzServiceClientFactory(
+      AuthenticationMethod method,
+      std::unique_ptr<SessionAuthzServiceClient> client)
+      : method_(method), client_(std::move(client)) {}
+
+  std::unique_ptr<SessionAuthzServiceClient> Create() override {
+    return std::move(client_);
+  }
+
+  AuthenticationMethod method() override { return method_; }
+
+ protected:
+  ~FakeSessionAuthzServiceClientFactory() override = default;
+
+ private:
+  AuthenticationMethod method_;
+  std::unique_ptr<SessionAuthzServiceClient> client_;
+};
+
 }  // namespace
 
 class NegotiatingAuthenticatorTest : public AuthenticatorTestBase {
@@ -467,4 +492,74 @@
   EXPECT_EQ(client, nullptr);
 }
 
+TEST_F(NegotiatingAuthenticatorTest,
+       CreateHostAuthenticator_SharedSecret_SynchronousTeardown) {
+  auto auth_config =
+      std::make_unique<HostAuthenticationConfig>(host_cert_, key_pair_);
+  auth_config->AddSharedSecretAuth("hash");
+  auto host = std::make_unique<NegotiatingHostAuthenticator>(
+      kHostJid, kClientJid, std::move(auth_config));
+
+  JingleAuthentication client_message;
+  client_message.method = AuthenticationMethod::SHARED_SECRET_SPAKE2_CURVE25519;
+
+  // This should not crash.
+  host->ProcessMessage(client_message,
+                       base::BindLambdaForTesting([&]() { host.reset(); }));
+
+  EXPECT_EQ(host, nullptr);
+}
+
+TEST_F(NegotiatingAuthenticatorTest,
+       CreateHostAuthenticator_Pairing_SynchronousTeardown) {
+  auto pairing_registry = base::MakeRefCounted<SynchronousPairingRegistry>(
+      std::make_unique<MockPairingRegistryDelegate>());
+  auto auth_config =
+      std::make_unique<HostAuthenticationConfig>(host_cert_, key_pair_);
+  auth_config->AddPairingAuth(pairing_registry);
+  auth_config->AddSharedSecretAuth("hash");
+  auto host = std::make_unique<NegotiatingHostAuthenticator>(
+      kHostJid, kClientJid, std::move(auth_config));
+
+  JingleAuthentication client_message;
+  client_message.method = AuthenticationMethod::PAIRED_SPAKE2_CURVE25519;
+
+  // This should not crash.
+  host->ProcessMessage(client_message,
+                       base::BindLambdaForTesting([&]() { host.reset(); }));
+
+  EXPECT_EQ(host, nullptr);
+}
+
+TEST_F(NegotiatingAuthenticatorTest,
+       CreateHostAuthenticator_SessionAuthz_SynchronousTeardown) {
+  auto mock_client = std::make_unique<MockSessionAuthzServiceClient>();
+  EXPECT_CALL(*mock_client, GenerateHostToken(_))
+      .WillOnce([](MockSessionAuthzServiceClient::GenerateHostTokenCallback
+                       callback) {
+        std::move(callback).Run(
+            HttpStatus(HttpStatus::Code::PERMISSION_DENIED, "denied"), nullptr);
+      });
+
+  auto factory = base::MakeRefCounted<FakeSessionAuthzServiceClientFactory>(
+      AuthenticationMethod::CLOUD_SESSION_AUTHZ_SPAKE2_CURVE25519,
+      std::move(mock_client));
+
+  auto auth_config =
+      std::make_unique<HostAuthenticationConfig>(host_cert_, key_pair_);
+  auth_config->AddSessionAuthzAuth(factory);
+  auto host = std::make_unique<NegotiatingHostAuthenticator>(
+      kHostJid, kClientJid, std::move(auth_config));
+
+  JingleAuthentication client_message;
+  client_message.method =
+      AuthenticationMethod::CLOUD_SESSION_AUTHZ_SPAKE2_CURVE25519;
+
+  // This should not crash.
+  host->ProcessMessage(client_message,
+                       base::BindLambdaForTesting([&]() { host.reset(); }));
+
+  EXPECT_EQ(host, nullptr);
+}
+
 }  // namespace remoting::protocol
Loading diff…

Original Bug Report

reported by [email protected]

Potential Use-After-Free in NegotiatingHostAuthenticator::CreateAuthenticator

Flapjack, 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 pre-authentication Use-After-Free (UAF) vulnerability exists in Chrome Remote Desktop’s NegotiatingHostAuthenticator. During authentication setup, an invalid initial message can synchronously trigger session failure and object destruction during a nested callback. Upon returning from the callback, execution attempts to access members of the now-freed authenticator instance, creating an RCE primitive.

Affected files:

  • remoting/protocol/negotiating_host_authenticator.cc

Estimated timestamp from git blame: 2024-02-23

Summary

A potential Use-After-Free (UAF) vulnerability has been identified in NegotiatingHostAuthenticator::CreateAuthenticator within the Chrome Remote Desktop host (remoting_host). The vulnerability is triggered when an incoming authentication message is synchronously rejected during the initialization of an underlying authenticator. This synchronous rejection forces the immediate closure of the Jingle session, which deletes the NegotiatingHostAuthenticator instance. Execution then proceeds back up the stack to access a member variable of the freed this pointer.

Technical Details

In remoting/protocol/negotiating_host_authenticator.cc, the CreateAuthenticator method initializes underlying authenticators. For several negotiation paths, a resume_callback is executed synchronously before the function returns. If the execution of this callback results in the destruction of the session, a UAF occurs.

Below is a potential step-by-step execution flow an attacker could use to trigger the vulnerability. (Note: These are suggested steps based on static code analysis, as we do not have an actively running exploit proof-of-concept).

  1. An unauthenticated attacker connects to the host and sends a session-initiate Jingle signaling message.
  2. In this message, they request the SHARED_SECRET_SPAKE2_CURVE25519 method, but intentionally provide a malformed payload (e.g., an empty <spake-message>).
  3. JingleSession::AcceptIncomingConnection begins processing the request and passes the message to a newly created NegotiatingHostAuthenticator.
  4. NegotiatingHostAuthenticator::ProcessMessage selects the attacker’s preferred method and calls CreateAuthenticator(), passing a resume_callback that wraps ProcessMessageInternal.
  5. CreateAuthenticator handles the SHARED_SECRET_SPAKE2_CURVE25519 path (lines 183-188). It instantiates Spake2Authenticator::CreateForHost and assigns it to this->current_authenticator_.
  6. At line 187, it synchronously invokes the callback: std::move(resume_callback).Run();.
  7. This executes ProcessMessageInternal, which passes the malformed payload to the underlying Spake2Authenticator::ProcessMessage.
  8. Spake2Authenticator encounters the empty <spake-message>, sets its state to REJECTED, and fires its own state-update callbacks.
  9. This rapidly propagates the REJECTED state back to JingleSession::ContinueAcceptIncomingConnection, which immediately invokes Close().
  10. Close() triggers a session failure cascade: ClientSession::OnConnectionClosed is called, which notifies ChromotingHost::OnSessionClosed.
  11. ChromotingHost synchronously erases the ClientSession from its internal map, which deletes the JingleSession object and, finally, the NegotiatingHostAuthenticator (this).
  12. The call stack unwinds back to NegotiatingHostAuthenticator::CreateAuthenticator at line 191:
191:   ChainStateChangeAfterAcceptedWithUnderlying(*current_authenticator_);
  1. The execution dereferences this->current_authenticator_ on the freed object. This attempts to write a base::RepeatingCallback to freed memory inside Authenticator::ChainStateChangeAfterAcceptedWithUnderlying, providing a robust primitive for memory corruption and potential Remote Code Execution (RCE) in the unsandboxed host process.

Suggested Fix

Similar to how a previous vulnerability was fixed in the client-side equivalent (NegotiatingClientAuthenticator), NegotiatingHostAuthenticator::CreateAuthenticator should check if the object is still alive after invoking the resume_callback.

This can be safely implemented using base::WeakPtr:

  auto weak_this = weak_factory_.GetWeakPtr();
  std::move(resume_callback).Run();
  if (!weak_this) {
    return;
  }
  ChainStateChangeAfterAcceptedWithUnderlying(*current_authenticator_);

Evaluated with Chrome root at commit: 2155cb00003ec35716a76ed3246eae995f87b7ff


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