CVE-2025-31277
Overview
Impact:
Description: Processing maliciously crafted web content may lead to memory corruption
Researchers: Yuhao Hu, Yan Kang, Chenggang Wu, and Xiaojie Wei
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.
Patch Details
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
+}
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]]
Background
Advisory: Apple Security Advisory
| Attribute | Value |
|---|---|
| CVE | CVE-2025-31277 |
| Bugzilla | 291745 |
| Component | JSC |
| Bug Class | TypeConfusion |
| Severity | medium |
| Commit | 716536ce98d6f8d4… |
| Advisory | Apple Advisory |
Terminology
- 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.
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.
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.
Changed Functions
| Function | File | Change | Note |
|---|---|---|---|
tryCreateContiguousArrayWithPattern |
Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h |
modified | Returns nullptr when globalObject->isHavingABadTime(), forcing the safe (ArrayStorage) path instead of building a contiguous-indexing array during a bad time. |
Files Changed
Source Files
Source/JavaScriptCore/runtime/JSGlobalObjectInlines.h
Test Files
JSTests/stress/regexp-matches-array-should-respect-have-a-bad-time.js
Regression Test
The fix ships this proof-of-concept / regression test:
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
+}