This Week in WebKit — March 07–13, 2026
Featured
copyTextureToBuffer multiplies the y coordinate by bytesPerImage instead of bytesPerRow. Because bytesPerImage equals bytesPerRow times heightInRows, every row past the first overshoots by a factor of the texture height — for a 256-wide RGBA8 texture with height 4, row 1 lands at offset 4096 instead of 1024 and grows from there. A mirror bug in copyBufferToTexture undercounts the z-axis slice stride. Both Swift dimensions share UInt32 as their underlying type, so the swap was invisible to the type system; Jon Butler caught these by mechanically diffing the Swift implementation against its Objective-C++ reference.
MapIterationEntryKey was declared NodeResultInt32, telling JSC that Map.forEach keys are always unboxed 32-bit integers. They aren't; Map keys can be any JSValue. The fix is a one-token change in DFGNodeType.h, but the regression test reads like a weaponization sketch: warm DFG with a forEach loop, allocate a Map with an object key, GC-aided heap spray to reclaim the slot under wrong-type assumptions, then read the sprayed value back through the confused reference. The asymmetry with MapIterationEntryValue (correctly NodeResultJS) is exactly the smell that should have caught this in review.
When OMG compiles Wasm GC's struct.new_default, fields branch on width: ref types get jsNull, ≤4 bytes get an Int32 zero, everything else gets an Int64 zero. The implicit 'everything else' assumed 8 bytes — but Wasm GC also lets you put a 16-byte v128 there. Half the slot gets zeroed, the other half keeps whatever the allocator's backing store happened to hold. Read it back through i64x2.extract_lane 1 and you have 8 bytes of stale process memory per allocation, harvested directly as a JavaScript BigInt — pointer-sized, repeatable, and useful for ASLR bypass.
The Custom Highlight API lets the same Highlight live in multiple Documents' registries, and each Highlight owns Ranges that hold a Ref
WebKit replaces custom-scheme URLs with webkit-masked-url://hidden/ during DOM serialization so web pages can't fingerprint installed extensions. innerHTML went through serializeFragment with ResolveURLs::NoExcludingURLsForPrivacy; XMLSerializer.serializeToString called the exact same helper with ResolveURLs::No, leaving extension URLs untouched in the output. The fix flips one enum value. The lesson is older than the bug: any privacy invariant enforced at one serialization boundary has to hold at every serialization boundary.
Security fixes
-
WebGPU Shared-Memory TOCTOU Leading to Shader OOB Accesses
High WebKit GPU Process — WebGPU IPC (RemoteBuffer, RemoteQueue)
-
WGSL Override Validation Crash via Pack Wrapper Misclassification
Medium WebGPU WGSL Compiler (GlobalVariableRewriter, constant evaluator)
-
Wasm OMG Tail Call Scratch Register Corruption on ARM
High JSC Wasm OMG JIT — tail call implementation
-
Wasm OMG Tail Call F32 Spill Stack OOB Write
High JSC Wasm OMG JIT — tail call FPR spilling
-
ANGLE Metal BufferPool Integer Truncation
Medium ANGLE Metal backend — BufferPool
Notable development
-
JSC `using` Declarations (Explicit Resource Management)
feature
-
JSC `ArrayIsArray` DFG Intrinsic
optimization
-
Site Isolation: Cross-Site iframe history.back() Support
feature
-
IndexedDB Connection Recovery After Network Process Crash
bug
-
JSC RegExp#lastIndex Inline Cache
optimization
-
WGSL Uniformity Analysis Compiler Pass
feature