Medium CVSS 8.8 webkit Type Confusion CISA KEV 🔧 Commit mapped

Overview

Medium
Severity
8.8
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to memory corruption
ComponentJSC
Sub-componentJSC Runtime
Bug ClassType Confusion
Tracker291745
Fix commit716536ce98d6 (WebKit/WebKit) +16/-0
CWECWE-119, CWE-120 (Buffer bounds error, Buffer overflow)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CISA KEVListed
CreditedYuhao Hu, Yan Kang, Chenggang Wu, and Xiaojie Wei
Disclosed2025-07-29

Background

Having a bad time
JSC state entered when Array/Object.prototype gets indexed properties; fast indexed array storage becomes unsafe and arrays must use ArrayStorage.
ArrayWithContiguous
A fast array indexing type assuming dense storage and no interfering prototype accessors.
RegExp matches array
A consumer that uses the fast contiguous-array creation path, exercised by the exploit.

Root Cause Analysis

This fixes a type-confusion / memory-corruption bug where JavaScriptCore’s fast contiguous-array creation ignored the global object’s ‘having a bad time’ state. When Array.prototype or Object.prototype gains indexed properties (e.g. an indexed getter/setter), JSC enters isHavingABadTime(): fast contiguous/indexed array storage is no longer safe because indexed access must consult the prototype chain, so arrays must use the slower ArrayStorage path. tryCreateContiguousArrayWithPattern is a fast path (used for example when building RegExp matches arrays) that constructs an ArrayWithContiguous array directly. Pre-patch it checked length limits but did not check isHavingABadTime(), so during a bad time it still produced a contiguous-indexing array whose storage assumptions conflict with the prototype’s indexed accessors — later indexed reads/writes treat attacker-influenced state as fast contiguous storage, a type confusion leading to memory corruption.

The fix adds if (globalObject->isHavingABadTime()) return nullptr; so the caller falls back to the safe array-creation path.

The restored invariant is that fast contiguous-array creation is disabled whenever the global object is having a bad time. The regression test installs an indexed accessor (entering a bad time) and creates a RegExp matches array, then writes a large index.

Key insight
Fast contiguous-array creation skipped the isHavingABadTime() check, so it produced fast-indexed arrays exactly when the prototype’s indexed accessors make that unsafe; adding the check restores the safe fallback.

Attack Path

  1. Enter 'having a bad time' Define an indexed property (getter/setter) on Array.prototype or Object.prototype so the global object enters isHavingABadTime().
  2. Trigger fast array creation Cause a RegExp match (or other consumer) to call tryCreateContiguousArrayWithPattern, which pre-patch ignored the bad-time state.
  3. Obtain an inconsistent array Receive an ArrayWithContiguous array whose storage violates the bad-time invariant.
  4. Corrupt memory Indexed access on the array is type-confused against the prototype’s indexed accessors, yielding memory corruption in WebContent.

Impact Assessment

A type-confusion memory-corruption primitive in the WebContent process, triggerable from ordinary script by poisoning a prototype and forcing a fast array creation (e.g. via RegExp). Indexing-type confusions in JSC are historically strong routes to arbitrary read/write and code execution.

Changed Functions

FunctionChangeNotes
C4
JSTests/stress/regexp-matches-array-should-respect-have-a-bad-time.js
modified
for
JSTests/stress/regexp-matches-array-should-respect-have-a-bad-time.js
modified

Files Changed

  • JSTests/stress/regexp-matches-array-should-respect-have-a-bad-time.js
  • Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h

Audit Directions

  • Fast array-creation paths
    Grep JSGlobalObjectInlines and array-allocation helpers for tryCreate*Array / originalArrayStructureForIndexingType uses that omit an isHavingABadTime() guard.
  • Consumers of fast patterns
    Audit RegExp/spread/Array builtins that build arrays via fast patterns to confirm they honor the bad-time state.
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h b/Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h
index bfbf2bd6512a..13c7ce8ae40e 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h
@@ -332,6 +332,9 @@ ALWAYS_INLINE JSArray* tryCreateContiguousArrayWithPattern(JSGlobalObject* globa
     if (initialLength >= MIN_ARRAY_STORAGE_CONSTRUCTION_LENGTH)
         return nullptr;
 
+    if (globalObject->isHavingABadTime()) [[unlikely]]
+        return nullptr;
+
     VM& vm = globalObject->vm();
     Structure* structure = globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
     if (!hasContiguous(structure->indexingType())) [[unlikely]]
diff --git a/JSTests/stress/regexp-matches-array-should-respect-have-a-bad-time.js b/JSTests/stress/regexp-matches-array-should-respect-have-a-bad-time.js
new file mode 100644
index 000000000000..0cf373454d20
--- /dev/null
+++ b/JSTests/stress/regexp-matches-array-should-respect-have-a-bad-time.js
@@ -0,0 +1,13 @@
+function F0(){
+    class C4{}
+    function f5(a6,a7,a8){
+        return {__proto__:a7}
+    }
+    f5(C4,C4)
+    Object.defineProperty(C4, 8, {configurable:true, get: f5, set: f5})
+}
+for(let v11=0;v11<5;v11++){
+    v14 = ("size").match(/e/g)
+    new F0()
+    v14[41530] = v14
+}
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/JSTests/stress/regexp-matches-array-should-respect-have-a-bad-time.js b/JSTests/stress/regexp-matches-array-should-respect-have-a-bad-time.js
new file mode 100644
index 000000000000..0cf373454d20
--- /dev/null
+++ b/JSTests/stress/regexp-matches-array-should-respect-have-a-bad-time.js
@@ -0,0 +1,13 @@
+function F0(){
+    class C4{}
+    function f5(a6,a7,a8){
+        return {__proto__:a7}
+    }
+    f5(C4,C4)
+    Object.defineProperty(C4, 8, {configurable:true, get: f5, set: f5})
+}
+for(let v11=0;v11<5;v11++){
+    v14 = ("size").match(/e/g)
+    new F0()
+    v14[41530] = v14
+}
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker.