Overview

High
Severity
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactUse after free in FedCM
DescriptionUse after free in FedCM
ComponentFedCM
Bug ClassUAF
Tracker491869946
Fix commit392c4d50d407 (chromium/src) +42/-3
CISA KEVNot listed
CreditedShaheen Fazim
Disclosed2026-03-23

Files Changed

  • third_party/blink/renderer/modules/credentialmanagement/identity_provider.cc
  • third_party/blink/web_tests/external/wpt/fedcm/fedcm-authz/fedcm-resolve-side-effects.https.html
From 392c4d50d407236a3212d654cdea1fca202fd7ad Mon Sep 17 00:00:00 2001
From: Christian Biesinger <[email protected]>
Date: Mon, 16 Mar 2026 10:32:18 -0700
Subject: [PATCH] [FedCM] Get the FederatedAuthRequest right before using it

And only get it if the context is (still) valid.

[email protected]

Fixed: 491869946
Change-Id: I0552f07f7fbffc743a85f95a7026225987a55147
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/7665206
Commit-Queue: Christian Biesinger <[email protected]>
Reviewed-by: Nicolás Peña <[email protected]>
Auto-Submit: Christian Biesinger <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1599990}
---

diff --git a/third_party/blink/renderer/modules/credentialmanagement/identity_provider.cc b/third_party/blink/renderer/modules/credentialmanagement/identity_provider.cc
index 05e254e..364f6457 100644
--- a/third_party/blink/renderer/modules/credentialmanagement/identity_provider.cc
+++ b/third_party/blink/renderer/modules/credentialmanagement/identity_provider.cc
@@ -244,9 +244,6 @@
       MakeGarbageCollected<ScriptPromiseResolver<IDLUndefined>>(script_state);
   auto promise = resolver->Promise();
 
-  auto* request =
-      CredentialManagerProxy::From(script_state)->FederatedAuthRequest();
-
   std::unique_ptr<base::Value> token_base_value;
   if (RuntimeEnabledFeatures::FedCmNonStringTokenEnabled()) {
     std::unique_ptr<WebV8ValueConverter> converter =
@@ -322,6 +319,17 @@
         std::move(*token_base_value));
   }
 
+  if (!script_state->ContextIsValid()) {
+    // This can happen if converting the `token` parameter had side effects
+    // that destroyed the document. With an invalid context, we also can't
+    // reject the promise.
+    return promise;
+  }
+
+  // There must not be JavaScript execution between getting the request pointer
+  // and using it.
+  auto* request =
+      CredentialManagerProxy::From(script_state)->FederatedAuthRequest();
   request->ResolveTokenRequest(
       account_id, std::move(params),
       BindOnce(&OnResolveTokenRequest, WrapPersistent(resolver)));
diff --git a/third_party/blink/web_tests/external/wpt/fedcm/fedcm-authz/fedcm-resolve-side-effects.https.html b/third_party/blink/web_tests/external/wpt/fedcm/fedcm-authz/fedcm-resolve-side-effects.https.html
new file mode 100644
index 0000000..6a464e65
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fedcm/fedcm-authz/fedcm-resolve-side-effects.https.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>Federated Credential Management API network request tests.</title>
+<link rel="help" href="https://fedidcg.github.io/FedCM">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<body>
+
+<script type="module">
+
+promise_test(async t => {
+  const frame = document.createElement('iframe');
+  document.body.appendChild(frame);
+
+  const token = {};
+  Object.defineProperty(token, 'prop', {
+      get: function() {
+          frame.remove();
+          return "value";
+      },
+      enumerable: true
+  });
+
+  try {
+    frame.contentWindow.IdentityProvider.resolve(token, { accountId: '123' });
+  } catch(e) {}
+}, "If a getter in the token in IdentityProvider.resolve removes the frame, the user agent should not crash");
+
+</script>
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/third_party/blink/web_tests/external/wpt/fedcm/fedcm-authz/fedcm-resolve-side-effects.https.html b/third_party/blink/web_tests/external/wpt/fedcm/fedcm-authz/fedcm-resolve-side-effects.https.html
new file mode 100644
index 0000000..6a464e65
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fedcm/fedcm-authz/fedcm-resolve-side-effects.https.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<title>Federated Credential Management API network request tests.</title>
+<link rel="help" href="https://fedidcg.github.io/FedCM">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/resources/testdriver.js"></script>
+<script src="/resources/testdriver-vendor.js"></script>
+
+<body>
+
+<script type="module">
+
+promise_test(async t => {
+  const frame = document.createElement('iframe');
+  document.body.appendChild(frame);
+
+  const token = {};
+  Object.defineProperty(token, 'prop', {
+      get: function() {
+          frame.remove();
+          return "value";
+      },
+      enumerable: true
+  });
+
+  try {
+    frame.contentWindow.IdentityProvider.resolve(token, { accountId: '123' });
+  } catch(e) {}
+}, "If a getter in the token in IdentityProvider.resolve removes the frame, the user agent should not crash");
+
+</script>
Loading diff…

Original Bug Report

reported by [email protected]

heap-use-after-free in blink::IdentityProvider::resolve

=================================================================
==62372==ERROR: AddressSanitizer: heap-use-after-free on address 0x12be97ae9630 at pc 0x7ff858f0742e bp 0x00e6035fe160 sp 0x00e6035fe1a8
READ of size 8 at 0x12be97ae9630 thread T0
    #0 0x7ff858f0742d in blink::IdentityProvider::resolve(class blink::ScriptState *, class blink::ScriptValue const &, class blink::IdentityResolveOptions const *) C:\b\s\w\ir\cache\builder\src\third_party\blink\renderer\modules\credentialmanagement\identity_provider.cc:316:12
    #1 0x7ff85671195b in blink::`anonymous namespace'::v8_identity_provider::ResolveStaticOperationCallback C:\b\s\w\ir\cache\builder\src\out\069a-Win_ASan_Releas\gen\third_party\blink\renderer\bindings\modules\v8\v8_identity_provider.cc:204:23
    #2 0x7ff85e5f3824 in Builtins_CallApiCallbackGeneric (C:\Users\Admin\Downloads\chrome-asan\chrome.dll+0x1ad4d3824)
    #3 0x7ff85e5f197b in Builtins_InterpreterEntryTrampoline (C:\Users\Admin\Downloads\chrome-asan\chrome.dll+0x1ad4d197b)
    ...
    #35 0x7ff845866613 in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::DoWork(void) C:\b\s\w\ir\cache\builder\src\base\task\sequence_manager\thread_controller_with_message_pump_impl.cc:346:40
    #36 0x7ff8459d3607 in base::MessagePumpDefault::Run(class base::MessagePump::Delegate *) C:\b\s\w\ir\cache\builder\src\base\message_loop\message_pump_default.cc:42:55
    #37 0x7ff8458694ff in base::sequence_manager::internal::ThreadControllerWithMessagePumpImpl::Run(bool, class base::TimeDelta) C:\b\s\w\ir\cache\builder\src\base\task\sequence_manager\thread_controller_with_message_pump_impl.cc:650:12
    #38 0x7ff84590ef5c in base::RunLoop::Run(class base::Location const &) C:\b\s\w\ir\cache\builder\src\base\run_loop.cc:135:14

SUMMARY: AddressSanitizer: heap-use-after-free C:\b\s\w\ir\cache\builder\src\third_party\blink\renderer\modules\credentialmanagement\identity_provider.cc:316:12 in blink::IdentityProvider::resolve(class blink::ScriptState *, class blink::ScriptValue const &, class blink::IdentityResolveOptions const *)
Shadow bytes around the buggy address:
  0x12be97ae9380: f7 fa 00 fa f7 fa 00 fa f7 fa 00 fa f7 fa 00 fa
  0x12be97ae9400: f7 fa fd fa f7 fa fd fa f7 fa fd fa f7 fa fd fa
  0x12be97ae9480: f7 fa 00 fa f7 fa fd fd f7 fa fd fa f7 fa fd fa
  0x12be97ae9500: f7 fa fd fa f7 fa 00 07 f7 fa fd fa f7 fa fd fa
  0x12be97ae9580: f7 fa fd fa f7 fa fd fa f7 fa fd fa f7 fa 00 fa
=>0x12be97ae9600: f7 fa fd fd f7 fa[fd]fd f7 fa fd fa f7 fa fd fa
  0x12be97ae9680: f7 fa fd fa f7 fa fd fd f7 fa fd fa f7 fa fd fa
  0x12be97ae9700: f7 fa fd fa f7 fa fd fa f7 fa 00 00 f7 fa fd fa
  0x12be97ae9780: f7 fa 00 00 f7 fa 00 00 f7 fa 00 00 f7 fa 00 fa
  0x12be97ae9800: f7 fa fd fd f7 fa fd fa f7 fa fd fa f7 fa fd fd
  0x12be97ae9880: f7 fa 00 fa f7 fa fd fa f7 fa fd fa f7 fa fd fa
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

==62372==ADDITIONAL INFO

==62372==Note: Please include this section with the ASan report.
Task trace:
    #0 0x7ff855e7d154 in blink::DOMTimer::DOMTimer(class blink::ExecutionContext &, class blink::ScheduledAction *, class base::TimeDelta, bool) C:\b\s\w\ir\cache\builder\src\third_party\blink\renderer\core\scheduler\dom_timer.cc:343:27
    #1 0x7ff849446109 in IPC::ChannelAssociatedGroupController::Accept(class mojo::Message *) C:\b\s\w\ir\cache\builder\src\ipc\ipc_mojo_bootstrap.cc:1138:13


Command line: `"C:\Users\Admin\Downloads\chrome-asan\chrome.exe" --type=renderer --no-pre-read-main-dll --start-stack-profiler --no-sandbox --file-url-path-alias="/gen=C:\Users\Admin\Downloads\chrome-asan\gen" --video-capture-use-gpu-memory-buffer --lang=en-US --device-scale-factor=1 --num-raster-threads=4 --enable-main-frame-before-activation --renderer-client-id=5 --time-ticks-at-unix-epoch=-1773079218143692 --launch-time-ticks=197939893276 --metrics-shmem-handle=3844,i,15911451909191243047,11158795503653610499,2097152 --field-trial-handle=1940,i,1091808593593248265,3138818943078118960,262144 --variations-seed-version --pseudonymization-salt-handle=2108,i,7123884904703337945,13134237462315843116,4 --trace-process-track-uuid=3190708990997080739 --mojo-platform-channel-handle=3780 /prefetch: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.

==62372==END OF ADDITIONAL INFO

==62372==ABORTING

VERSION

148.0.7730.0 (Developer Build) (64-bit)

REPRODUCTION CASE

Build: asan-win32-release_x64-1598047

Run: ./chrome.exe --no-sandbox poc.html


Reporter credit: Shaheen Fazim

View on issue tracker