# Async callback outlives captured object

Raw this or pointer captured in async task, dispatch, or reply handler with no lifetime guarantee

_Area: Memory corruption and native code. Seen in 5 disclosed reports; 2 confirmed bounties: $8,000 and $215,000; latest 2023-10-11. Updated 2026-10-23._

## How it works
An asynchronous operation (a posted task, a cross-thread dispatch, an XPC reply handler, an in-flight navigation) captures a raw pointer or raw `this` to an object. The object's lifetime is governed by something else: a refcount, a GC, or another thread that can free it. The async side assumes the object is still alive when the callback runs, but nothing keeps it alive. If the object is freed first, the callback dereferences or releases stale memory.

## Where it shows up
- `PostTaskAndReply` / `createCrossThreadTask` / `dispatch_async` capturing raw `this` or a raw member pointer.
- Ref-counted cross-thread task templates whose trait check matches a base class, not the exact derived type.
- XPC multi-message handlers storing raw sub-message pointers in a stack array, conditionally replaced with retained pointers.
- Observer registration (`AddObserver`) without a matching `RemoveObserver` on teardown [E1](https://bugbountylibrary.com/r/blog%3Amicrosoftedge-github-io-edgevr-posts-memory-corruption-vulnerabilities-in-edge.md).
- Native objects exposing a sub-object as a plain JS property, with callbacks bound via `base::Unretained` [E3](https://bugbountylibrary.com/r/h1%3A1977252.md).
- Navigation or activation code that dereferences a page-owned object after a reload [E4](https://bugbountylibrary.com/r/blog%3Ablog-redteam-pl-2019-12-chrome-portal-element-fuzzing-html.md).
- Adjacent (not async-lifetime): missing `end()` checks on frame/iterator vectors, an OOB-read [E1](https://bugbountylibrary.com/r/blog%3Amicrosoftedge-github-io-edgevr-posts-memory-corruption-vulnerabilities-in-edge.md).

## How to review
For every async callback, identify what keeps the captured object alive until the callback runs. The invariant: the callback must hold a strong reference (or a weak pointer with a liveness check) for its entire lifetime. For refcounted releases, the invariant is that a release must correspond to a reference actually taken: release only a slot that was overwritten with a retained pointer, never a raw one, or the refcount drops below zero (invalid free). Check that the refcount trait matches the exact template argument, not a base; that every observer add has a matching remove; that stack arrays of raw pointers are not conditionally overwritten with retained pointers and then released uniformly; that a sub-object cannot outlive its parent while a callback still points at the parent; and that navigation code revalidates the object after a reload.

## Variants seen
- Cross-thread task template picks the raw-reference path because the derived class inherits `ThreadSafeRefCounted<Base>` [E2](https://bugbountylibrary.com/r/p0%3ACVE-2021-30858.md).
- XPC multi-message handler mixes raw and retained pointers, then releases a reference never obtained [E5](https://bugbountylibrary.com/r/p0%3ACVE-2019-7286.md).
- Browser-process dialogs and features capture raw `this` in posted tasks [E1](https://bugbountylibrary.com/r/blog%3Amicrosoftedge-github-io-edgevr-posts-memory-corruption-vulnerabilities-in-edge.md).
- JS-retained sub-object outlives the native parent bound with `base::Unretained` [E3](https://bugbountylibrary.com/r/h1%3A1977252.md).
- In-flight navigation dereferences a freed portal object after page reload (navigation-lifetime, not refcount) [E4](https://bugbountylibrary.com/r/blog%3Ablog-redteam-pl-2019-12-chrome-portal-element-fuzzing-html.md).

## Why fixes fail
Fork-overridden methods can reintroduce a bug fixed upstream, so re-test against the fork [E1](https://bugbountylibrary.com/r/blog%3Amicrosoftedge-github-io-edgevr-posts-memory-corruption-vulnerabilities-in-edge.md). Trait-mismatch fixes must be re-checked whenever a new derived type is added [E2](https://bugbountylibrary.com/r/p0%3ACVE-2021-30858.md).

## Impact and severity
Use-after-free and invalid free leading to crashes and memory corruption, and in the XPC case a sandbox escape from a renderer [E5](https://bugbountylibrary.com/r/p0%3ACVE-2019-7286.md). Browser-process UAFs crash the browser and may be exploitable [E1](https://bugbountylibrary.com/r/blog%3Amicrosoftedge-github-io-edgevr-posts-memory-corruption-vulnerabilities-in-edge.md)[E4](https://bugbountylibrary.com/r/blog%3Ablog-redteam-pl-2019-12-chrome-portal-element-fuzzing-html.md). Severity is highest when the freed object is reachable from a sandboxed context and the heap can be groomed, as in [E5](https://bugbountylibrary.com/r/p0%3ACVE-2019-7286.md).

## Evidence
- E1: https://bugbountylibrary.com/r/blog%3Amicrosoftedge-github-io-edgevr-posts-memory-corruption-vulnerabilities-in-edge.md
- E2: https://bugbountylibrary.com/r/p0%3ACVE-2021-30858.md
- E3: https://bugbountylibrary.com/r/h1%3A1977252.md
- E4: https://bugbountylibrary.com/r/blog%3Ablog-redteam-pl-2019-12-chrome-portal-element-fuzzing-html.md
- E5: https://bugbountylibrary.com/r/p0%3ACVE-2019-7286.md
