High firefox UAF 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUse-after-free in the Networking: HTTP component
ComponentNetworking
Bug ClassUAF
Tracker2036929
Fix commitfe5e3b80b3a5 (firefox) +2/-1
CISA KEVNot listed
CreditedZijie Zhao
Disclosed2026-06-16

Background

`nsHttpChannel`
Gecko’s concrete HTTP channel implementation in the Networking: HTTP component that drives a request/response lifecycle and dispatches events to its listener.
`nsIStreamListener` / `OnStopRequest`
the listener callback interface whose OnStopRequest method signals a channel that data delivery has finished.
`mListener`
the nsHttpChannel member holding a reference to the stream listener that receives OnStartRequest/OnDataAvailable/OnStopRequest notifications.
`nsCOMPtr`
a smart pointer that owns a strong (refcounted) reference to an XPCOM object, keeping it alive for the pointer’s scope.

Root Cause Analysis

In nsHttpChannel::ContinueOnStopRequest, the terminal notification was dispatched by dereferencing the raw member pointer directly as mListener->OnStopRequest(this, aStatus). Because OnStopRequest runs arbitrary listener code, that callback (or reentrancy it triggers, such as tearing down or reassigning the channel’s listener chain) can drop the last strong reference to the object that mListener points at, freeing it while the virtual call is still in progress. The invariant violated is that a callee must remain alive for the full duration of a call made through a pointer to it; here no local strong reference guarded the listener across the OnStopRequest invocation.

The fix copies mListener into a local nsCOMPtr<nsIStreamListener> listener before invoking the method, so the listener holds an owning reference on the stack that outlives the call regardless of what the callback does to mListener. This closes the use-after-free window without changing the notification semantics.

Key insight
The core mistake was calling a reentrant listener callback through a raw member pointer that the callback itself could cause to be freed; the fix pins the listener with a stack nsCOMPtr strong reference for the duration of the call.

Attack Path

  1. Initiate a request Attacker-controlled content starts an HTTP load handled by an nsHttpChannel whose listener chain includes code the attacker can influence.
  2. Reach request completion Drive the channel to the stop phase so ContinueOnStopRequest fires mListener->OnStopRequest.
  3. Drop the listener during the callback From within OnStopRequest, cause the last strong reference to the target listener to be released (for example by tearing down or reassigning mListener), freeing it mid-call.
  4. Use the freed object The in-flight virtual dispatch and any continued use operate on freed memory, yielding a use-after-free.

Impact Assessment

An attacker who can shape a channel’s listener behavior gains a use-after-free triggered at HTTP request completion, corrupting freed heap memory that could be leveraged toward controlled reuse. This occurs in the process running the networking/HTTP stack during normal request teardown. The precondition is the ability to induce the listener to be released from inside its own OnStopRequest callback.

Files Changed

  • netwerk/protocol/http/nsHttpChannel.cpp

Audit Directions

  • Raw member-pointer callbacks
    Flag any mSomething->Method(...) where Method runs external or reentrant code and no local nsCOMPtr/strong reference guards the callee for the call’s duration.
  • Listener lifecycle around `OnStopRequest`/`OnStartRequest`
    Review channel and stream code paths where completion callbacks can reassign or release mListener, ensuring a stack-owned reference wraps each invocation.
  • Reentrancy during teardown
    Audit stop/cancel/finalize paths that dispatch to observers or listeners, checking that objects are refcount-pinned before any callback that could free them.
diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
index 6a0f61ad92c..337b24d2576 100644
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -10472,7 +10472,8 @@ nsresult nsHttpChannel::ContinueOnStopRequest(nsresult aStatus, bool aIsFromNet,
     MOZ_ASSERT(!LoadOnStopRequestCalled(),
                "We should not call OnStopRequest twice");
     StoreOnStopRequestCalled(true);
-    mListener->OnStopRequest(this, aStatus);
+    nsCOMPtr<nsIStreamListener> listener(mListener);
+    listener->OnStopRequest(this, aStatus);
   }
   StoreOnStopRequestCalled(true);
 
Loading diff…