Released June 29, 2026

CVE-2026-43734

CVSS 6.5 severity medium CWE-416 vector CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H

Overview

Impact:

Description: Processing maliciously crafted web content may lead to an unexpected process crash

Researchers: Jonathan Alush-Aben

Key insight. A cross-thread hand-off captured non-thread-safe WTF String/Vector members by reference instead of deep-copying them; even though the caller waits, sharing reference-counted buffers across threads is a use-after-free waiting to happen, and the fix is to pass an isolatedCopy/crossThreadCopy instead.

Patch Details

diff --git a/Source/WebCore/Modules/mediasource/MediaSource.cpp b/Source/WebCore/Modules/mediasource/MediaSource.cpp
index 035b6ad444fb..140425a7964a 100644
--- a/Source/WebCore/Modules/mediasource/MediaSource.cpp
+++ b/Source/WebCore/Modules/mediasource/MediaSource.cpp
@@ -1188,7 +1188,7 @@ bool MediaSource::isTypeSupported(ScriptExecutionContext& context, const String&
     }
 
     MediaPlayer::SupportsType supported;
-    callOnMainThreadAndWait([&] {
+    callOnMainThreadAndWait([&supported, parameters = crossThreadCopy(WTF::move(parameters))] {
         supported = MediaPlayer::supportsType(parameters);
     });
 
diff --git a/Source/WebCore/platform/graphics/MediaPlayer.cpp b/Source/WebCore/platform/graphics/MediaPlayer.cpp
index 352492014a02..21942ae9bd34 100644
--- a/Source/WebCore/platform/graphics/MediaPlayer.cpp
+++ b/Source/WebCore/platform/graphics/MediaPlayer.cpp
@@ -116,6 +116,24 @@ namespace WebCore {
 WTF_MAKE_TZONE_ALLOCATED_IMPL(MediaPlayer);
 WTF_MAKE_TZONE_ALLOCATED_IMPL(MediaPlayerFactory);
 
+MediaEngineSupportParameters MediaEngineSupportParameters::isolatedCopy() &&
+{
+    SUPPRESS_UNCOUNTED_ARG return {
+        crossThreadCopy(WTF::move(type)),
+        crossThreadCopy(WTF::move(url)),
+        isMediaSource,
+        isMediaStream,
+        requiresRemotePlayback,
+        supportsLimitedMatroska,
+        crossThreadCopy(WTF::move(contentTypesRequiringHardwareSupport)),
+        crossThreadCopy(WTF::move(allowedMediaContainerTypes)),
+        crossThreadCopy(WTF::move(allowedMediaCodecTypes)),
+        WTF::move(allowedMediaVideoCodecIDs),
+        WTF::move(allowedMediaAudioCodecIDs),
+        WTF::move(allowedMediaCaptionFormatTypes),
+    };
+}
+
 // a null player to make MediaPlayer logic simpler
 
 class NullMediaPlayerPrivate final : public MediaPlayerPrivateInterface, public ThreadSafeRefCounted<NullMediaPlayerPrivate, WTF::DestructionThread::Main> {
diff --git a/Source/WebCore/platform/graphics/MediaPlayer.h b/Source/WebCore/platform/graphics/MediaPlayer.h
index 5d8e3b632bdc..a634f3e95955 100644
--- a/Source/WebCore/platform/graphics/MediaPlayer.h
+++ b/Source/WebCore/platform/graphics/MediaPlayer.h
@@ -122,6 +122,8 @@ struct MediaEngineSupportParameters {
     std::optional<Vector<FourCC>> allowedMediaVideoCodecIDs;
     std::optional<Vector<FourCC>> allowedMediaAudioCodecIDs;
     std::optional<Vector<FourCC>> allowedMediaCaptionFormatTypes;
+
+    WARN_UNUSED_RETURN WEBCORE_EXPORT MediaEngineSupportParameters isolatedCopy() &&;
 };
 
 struct SeekTarget {

Background

Advisory: Apple Security Advisory

Attribute Value
CVE CVE-2026-43734
Bugzilla 313693
Component WebCore
Bug Class UAF
Severity medium
Commit 5b76ce8531919008…
Advisory Apple Advisory

Terminology

  • callOnMainThreadAndWait — A WTF helper that dispatches a task to the main thread and blocks the calling thread until it finishes, used when a non-main thread needs a main-thread-only API.
  • crossThreadCopy / isolatedCopy — WTF facilities that produce a deep, self-owned copy of a value (including its reference-counted String/Vector buffers) so it can be safely handed to another thread without sharing state.
  • MediaEngineSupportParameters — A WebCore struct bundling the content type, URL, and allowed container/codec/caption type lists used to ask a media engine whether it can play a given type.
  • Non-thread-safe String/Vector — WTF::String and Vector use reference counting and shared backing stores that are cheap to copy on one thread but unsafe to share or mutate concurrently across threads.
  • Lambda capture by reference ([&]) — Captures surrounding locals by reference so the closure accesses the originals; across a thread boundary this shares the very objects the other thread must not touch.

Root Cause Analysis

MediaSource::isTypeSupported runs on a worker/script thread but must query MediaPlayer::supportsType, which has to execute on the main thread. To do so it used callOnMainThreadAndWait with a lambda that captured the local MediaEngineSupportParameters by reference ([&]) and then called MediaPlayer::supportsType(parameters) on the main thread. MediaEngineSupportParameters is a struct containing String and Vector<String>/Vector<FourCC> members (type, url, contentTypesRequiringHardwareSupport, allowedMediaContainerTypes/CodecTypes, etc.). These WTF String/Vector types are reference-counted/heap-backed but are NOT thread-safe to share across threads by reference: passing them by reference means the main thread touches the same underlying buffers that the originating thread owns, violating the invariant that cross-thread work must operate on data that has been deep-copied (crossThreadCopy / isolatedCopy) into thread-owned storage. Although callOnMainThreadAndWait blocks the caller until the main-thread task completes, capturing by reference still lets the two threads concurrently reference the same non-thread-safe String/Vector internals during the hand-off, and any implicit ref/deref, copy, or internal mutation of those shared buffers from the main thread races with the worker thread’s ownership, leading to use-after-free / heap corruption of the string buffers. The fix changes the capture to [&supported, parameters = crossThreadCopy(WTF::move(parameters))], deep-copying the parameters into a thread-safe isolated copy that the main-thread lambda solely owns, so no non-thread-safe buffer is shared across the boundary. To support that, a new MediaEngineSupportParameters::isolatedCopy() && rvalue-qualified method is added in MediaPlayer.cpp/.h that crossThreadCopy()s each string/vector member and moves the trivially-copyable/plain members, giving crossThreadCopy a correct per-field deep-copy for this struct. The restored invariant is: values handed to another thread must be isolated copies with no shared reference-counted state.

Attack Path

1. Run isTypeSupported off the main thread

From maliciously crafted web content, invoke MediaSource.isTypeSupported(…) (or a code path reaching MediaSource::isTypeSupported) from a Worker or other non-main script thread so the callOnMainThreadAndWait hand-off is exercised.

2. Supply complex type parameters

Pass a content type / codec string that populates the String and Vector members of MediaEngineSupportParameters (type, allowed container/codec type lists), maximizing the reference-counted buffers shared by reference across the thread boundary.

3. Race the shared buffers

Cause the worker thread and the main thread to touch the same non-thread-safe String/Vector internals during the hand-off, so ref/deref or buffer access on one thread races the other’s ownership (inference: precise timing/interleaving needed to win the race is not shown by the diff).

4. Trigger use-after-free

The race frees or corrupts a String/Vector backing buffer while the other thread still references it, producing a use-after-free within WebCore’s media pipeline.

5. Crash the process

Per the advisory this yields an unexpected process crash; escalation beyond a crash would require additional heap-grooming and a separate corruption primitive not established by this commit.

Impact Assessment

The primitive is a use-after-free / cross-thread data race on reference-counted String/Vector buffers in the WebCore media pipeline, which the advisory characterizes as an unexpected process crash. Realistic escalation to a controlled corruption primitive would require reliably winning the hand-off race and grooming the freed buffer, which the diff does not establish; the most reliable outcome is a crash. It is confined to the process hosting the media/MediaSource logic (WebContent, or the GPU process where media decoding is offloaded) and remains within that sandbox.

Audit Directions

Other by-reference captures into callOnMainThread*

Grep WebCore for callOnMainThreadAndWait and callOnMainThread lambdas that capture [&] or [&, …] and inspect whether any captured local holds String/Vector/RefPtr state shared across the boundary rather than a crossThreadCopy.

Structs handed cross-thread without isolatedCopy

Search for crossThreadCopy(…) usages and, conversely, structs with String/Vector members passed into cross-thread dispatch (dispatchToMainThread, Function, CrossThreadTask) that lack an isolatedCopy()&& overload; a missing isolatedCopy is the tell.

Media parameter plumbing across threads

Audit MediaSource, SourceBuffer, and MediaPlayer paths that bridge worker/script threads to the main thread with MediaEngineSupportParameters or similar content-type structs, verifying each hand-off deep-copies rather than referencing caller-owned buffers.

Changed Functions

Function File Change Note
MediaSource::isTypeSupported Source/WebCore/Modules/mediasource/MediaSource.cpp modified Changed the callOnMainThreadAndWait lambda from capturing parameters by reference ([&]) to capturing a deep isolated copy ([&supported, parameters = crossThreadCopy(WTF::move(parameters))]) so the main thread no longer shares the caller’s non-thread-safe String/Vector buffers.
MediaEngineSupportParameters::isolatedCopy() && Source/WebCore/platform/graphics/MediaPlayer.cpp added New rvalue-qualified method that crossThreadCopy()s each String/Vector member (type, url, contentTypesRequiringHardwareSupport, allowed container/codec type lists) and moves the plain members, providing a correct cross-thread deep copy of the struct.
MediaEngineSupportParameters (struct declaration) Source/WebCore/platform/graphics/MediaPlayer.h modified Declared WARN_UNUSED_RETURN WEBCORE_EXPORT MediaEngineSupportParameters isolatedCopy() && so crossThreadCopy can produce a thread-owned copy of the parameters.

Files Changed

Source Files

  • Source/WebCore/Modules/mediasource/MediaSource.cpp
  • Source/WebCore/platform/graphics/MediaPlayer.cpp
  • Source/WebCore/platform/graphics/MediaPlayer.h