This Week in WebKit — June 06 - June 12, 2026
Featured
A media element outlives the document that owned it, still caching a root pointer into freed memory. The repair pass that should have fixed it decided there was nothing to fix.
A String.prototype.at call returns a code unit from a freed buffer — plain JavaScript, no flags. The read is the whole primitive; what kills the buffer mid-call is the surprise.
Any page can hand native code a plain object where a JSPromise belongs, and the guard beneath the cast was unreachable. The timing of the swap is the elegant part.
A live Range plus a DOM mutation loop puts a marker thread on the wrong side of a Ref assignment. Winning the window is the hard part — it is a few instructions wide.
A background fetch chunk invokes a callback while an iterator into the same map is still live. The sibling function was patched for exactly this; nobody came back for this one.
Security fixes
- YARR RegularExpression out-of-bounds write with duplicate named capture groups
- Range boundary-point lock discipline follow-up
Notable development
Other security-relevant changes
- [WebCore DOM Range] (Data race UAF)
ab48873— Range의 boundary point인 m_start, m_end를 변경할 때 locking이 추가되어, garbage collection 도중 동시 수정으로 인해 container node가 use-after-free 상태가 되는 문제를 방지합니다. - [WebCore Streams] (type confusion)
96ec73a— ReadableStream의 cancel handler에서 jsCast가 jsDynamicCast로 교체되어, 가짜 Promise 객체가 runtime check를 우회해 메모리를 손상시키는 type confusion을 방지합니다. - [WebCore DOM] (UAF)
934ecdc— 노드가 detach될 때 m_shadowIncludingRoot가 초기화되지 않아 stale 상태로 남던 문제로 인해 발생하던 Node::shadowIncludingRoot의 heap use-after-free가 수정되었습니다. - [JSC DFG] (type confusion)
c7fe05e— DFG JIT의 typeof/ToBoolean/CompareEq constant folding이 MasqueradesAsUndefined 객체의 realm-dependent semantics를 반영하도록 수정되어, cross-realm check에서 발생하던 type confusion이 방지됩니다. - [JSC BBQJIT] (aliasing)
a6f42da— BBQJIT의 tail call shuffle에서 16바이트로 정렬된 caller temp와 packed callee argument(v128 range 등) 간 stack slot 겹침을 감지하지 못하던 문제가 수정되었습니다. 이 문제로 인해 source value가 최종 위치로 이동되기 전에 덮어써질 가능성이 있었습니다. - [GPU Process AVF image decoder] (IPC boundary validation)
2f07319— remote AVF image decoder를 생성하기 전에 MIME type 지원 여부를 검증하는 MESSAGE_CHECK가 GPU process 경계에 추가되었습니다. 이를 통해 WebProcess가 지원되지 않는 type을 IPC로 전달해 검증되지 않은 decoder 경로를 유발하는 상황을 방지합니다. - [WebCore FocusController] (UAF)
7aacc65— shadow tree 내부의 focus된 element가 event 처리 도중 제거되어 garbage collect되는 경우, blur event dispatch에서 발생하던 use-after-free가 수정되었습니다. 패치 이전에는 해제된 메모리에 접근해 브라우저가 crash할 수 있었습니다. - [JSC FTL OSR] (hole handling)
392f508— operationPopulateObjectInOSR이 FTL OSR exit materialization 도중 기록되지 않은 array slot을 putDirectIndex에 전달하는 대신 정상적으로 건너뛰도록 수정되어, 초기화되지 않은 값이 잘못 처리되는 문제가 방지됩니다. - [WebKit focus / gesture validation] (validator bypass)
f3a769a— window 생성과 focus 연산 전반에 걸쳐 user gesture 소비 여부를 추적함으로써 popunder attack이 방지됩니다. SetFocus와 FocusRemoteFrame IPC에 UserGestureTokenIdentifier가 추가되어, gesture가 이미 소비된 경우 focus 요청을 거부합니다. - [WebCore SharedWorkerScriptLoader] (CSP bypass)
d65bd81— blob:/data: URL로 생성된 SharedWorker의 CSP 상속이 수정되었습니다. 이전에는 importScripts() 호출에서 생성 document의 CSP가 우회될 수 있었습니다. - [WebCore CSP] (policy loss)
f8ed382— setHTTPHeaderField()가 여러 CSP header를 append하지 않고 덮어쓰던 CSP policy 손실 문제가 수정되었습니다. 이제 blob: document는 마지막 policy만이 아니라 생성자의 모든 CSP policy를 정상적으로 상속받습니다. - [JSC DFG] (hardening)
0f5acb5— DFG가 Promise subclass에 대해서도 Promise.resolve를 identity로 잘못 folding하던 문제가 수정되었습니다. 이제 spec에 따라 builtin Promise에 한해서만 적용됩니다. - [JSC wasm] (race condition)
24362e6— WebAssembly name section parsing에서 compiler thread와 main thread가 동기화 없이 동시에 section에 접근할 수 있던 data race가 수정되었습니다. 이제 접근은 release/acquire accessor를 거치며, 최초 name section reference를 유지함으로써 lifetime safety도 보장됩니다. - [ANGLE validation] (OOB read)
08713e9— WebGL drawElements()에서 큰 UNSIGNED_INT index에 대한 validation이 잘못 수행되던 문제가, range check를 방해하던 잘못된 explicit static cast를 제거함으로써 수정되었습니다. 이 버그로 인해 attacker가 제어하는 index 값으로 out-of-bounds buffer access가 가능했을 것으로 보입니다. - [WebCore Streams] (UAF)
42ec79c— GC thread가 m_controller를 순회하는 도중 main thread에서 해당 객체가 해제될 수 있던 use-after-free가 수정되었습니다. 해결 방법으로 stream을 JSValueInWrappedObject 형태로 저장해, thread 경계를 넘나들며 정상적으로 관리되도록 했습니다. - [WebCore AV1 decoder] (Undefined left-shift)
74eb129— AV1 ULEB size decoding에서 uint8_t를 32비트 이상 left-shift할 때 parsing된 size가 손상될 수 있던 undefined behavior가 수정되었습니다. size_t로 casting함으로써 이 UB를 방지합니다. - [WebCore graphics] (OOB write)
d343d17— removeClient()에서 부호가 뒤바뀐 bounds check로 인해 잘못된 index에 접근할 때 out-of-bounds write가 발생하고, 정상적인 client 제거가 실패하던 문제가 수정되었습니다. - [WebCore CSP] (CSP bypass)
3ac584d— sandbox된 srcdoc iframe에서 meta CSP tag 처리 도중 상속받은 self-origin이 opaque origin으로 초기화되어 CSP 'self'가 우회되던 문제가 수정되었습니다. 이 문제로 인해 cross-origin base URL injection이 가능했습니다. - [WebCore WebGL] (UAF)
6eff33b— event loop task에 예약된 query 객체가 실행 전에 garbage collect될 수 있던 EXTDisjointTimerQuery의 use-after-free가 수정되었습니다. task가 완료될 때까지 객체가 유지되도록 적절한 ref-counting이 추가되었습니다. - [WebCore badging] (hardening)
3fa40e6— Navigator.setAppBadge/clearAppBadge에 same-origin check가 적용되어, W3C spec에 따라 cross-origin iframe이 app badge를 설정하지 못하도록 차단됩니다. 이전에는 cross-origin script도 성공할 수 있어 origin isolation이 위반되었습니다. - [WebKit Safe Browsing] (bypass)
0e4040c— COOP process swap 도중 lookup 결과가 response policy handler보다 먼저 도착하면 warning이 생략될 수 있던 safe browsing warning 우회 문제가 수정되었습니다. 이제 lookup이 완료되는 즉시 warning이 표시됩니다. - [WebCore DOM] (race condition)
f88c5d9— Node::traverseToOpaqueRoot의 race condition이 수정되었습니다. opaque root를 GC marking phase 도중 계산하는 대신 Node에 직접 저장하도록 변경하여, garbage collection 중 발생할 수 있던 concurrent-access 상황을 방지합니다. - [WebCore SpeechSynthesis] (null dereference)
ccfb13a— speech synthesis delegate callback에 null check가 추가되어, callback이 대기 중인 상태에서 m_synthesizerObject가 해제될 때 발생하던 null dereference crash가 방지됩니다. - [WebCore SourceBuffer] (crash)
1fd5d97— SourceBufferPrivate::removeCodedFramesInternal의 crash가 수정되었습니다. 잘못된 MediaTime 비교가 unordered 값을 반환하면서 guard를 우회하고, 유효하지 않은 시간 값이 map key로 사용될 수 있던 것이 원인이었습니다. - [WebCore Streams] (lifetime fix)
64ad3f3— stream.pipeTo()의 error 처리 도중 iframe이 detach되는 경우 StreamPipeToState::globalObject에서 발생하던 crash가 방지되었습니다. context->globalObject()가 null을 반환함에도 jsDynamicCast에서 확인 없이 dereference되던 것이 원인이었습니다.