CVE-2025-43421
Overview
Impact:
Description: Processing maliciously crafted web content may lead to an unexpected process crash
Researchers: Nan Wang (@eternalsakura13)
Key insight. This is a mitigation-by-disable: WebKit turned off the entire array-allocation-sinking optimization by default rather than fixing a specific check, which strongly implies an escape-analysis/materialization soundness bug in the JIT phase whose exact faulty predicate is not visible in this one-line diff.
Patch Details
diff --git a/Source/JavaScriptCore/runtime/OptionsList.h b/Source/JavaScriptCore/runtime/OptionsList.h
index 3d65cb28ba8e..5b0750dd2521 100644
--- a/Source/JavaScriptCore/runtime/OptionsList.h
+++ b/Source/JavaScriptCore/runtime/OptionsList.h
@@ -629,7 +629,7 @@ bool hasCapacityToUseLargeGigacage();
v(Bool, forceAllFunctionsToUseSIMD, false, Normal, "Force all functions to act conservatively w.r.t fp/vector registers for testing."_s) \
v(Bool, useOMGInlining, true, Normal, "Use OMG inlining"_s) \
v(Bool, freeRetiredWasmCode, true, Normal, "free BBQ/OMG-OSR wasm code once it's no longer reachable."_s) \
- v(Bool, useArrayAllocationSinking, true, Normal, nullptr) \
+ v(Bool, useArrayAllocationSinking, false, Normal, nullptr) \
v(Bool, dumpFTLCodeSize, false, Normal, nullptr) \
v(Bool, dumpOptimizationTracing, false, Normal, nullptr) \
v(Unsigned, markedBlockDumpInfoCount, 0, Normal, nullptr) /* FIXME: rdar://139998916 */ \
Background
Advisory: Apple Security Advisory
| Attribute | Value |
|---|---|
| CVE | CVE-2025-43421 |
| Bugzilla | 300718 |
| Component | JSC |
| Bug Class | OOB |
| Severity | medium |
| Commit | 56f026944a16a4ba… |
| Advisory | Apple Advisory |
Terminology
- Allocation sinking — A JIT optimization that removes or delays an object/array allocation when escape analysis proves the object is not observable, reconstructing it only where needed.
- Materialization — The point where a previously sunk allocation is actually built in memory, typically on an OSR-exit or merge path that requires a concrete object.
- OSR exit — On-stack replacement that bails from JIT-compiled code back to a lower tier, a common site where sunk allocations must be materialized correctly.
- Indexing type / butterfly — JSC array metadata describing element storage kind and the out-of-line backing store; an array whose indexing type or length is inconsistent leads to OOB or type-confused access.
- JSC runtime Option — A compile-time-listed, runtime-togglable flag in OptionsList.h; flipping its default changes engine behavior for all builds that do not override it.
Root Cause Analysis
The patch is a one-line change to Source/JavaScriptCore/runtime/OptionsList.h that flips the default value of the JSC runtime option useArrayAllocationSinking from true to false. Array allocation sinking is a DFG/FTL JIT optimization phase (implemented in Source/JavaScriptCore/dfg/DFGArrayAllocationSinkingPhase / the broader object-allocation-sinking machinery) that proves an allocated array does not escape and therefore removes or delays (sinks) the actual heap allocation, reconstructing (materializing) the object only on paths that need it, such as OSR exit. The vulnerable code is NOT in this diff; the diff only shows the mitigation of turning the optimization off by default. Inference: the underlying defect is a soundness bug in the allocation-sinking analysis or materialization logic, where the phase incorrectly concludes an array does not escape (or materializes it with wrong length/contents/type), so the optimized code operates on an object that either was never correctly allocated or was reconstructed with inconsistent metadata. The violated invariant is that a sunk allocation must be observationally identical to a real allocation for every path that can observe it: same butterfly/length, same indexing type, same initialization. When that invariant breaks, JIT-compiled code reads or writes through a phantom or mis-materialized array, producing the unexpected process crash noted in the advisory. The fix is blunt and conservative: rather than repairing the analysis, WebKit disabled the entire optimization by default, so no array allocation is ever sunk and the miscompilation path is unreachable. Because the fix is a default flip and not a localized correctness patch, the precise faulty predicate cannot be read off this diff and any statement about the exact escape-analysis mistake is inference, not established by the commit. The Normal option class means it remains togglable, but production builds now take the safe path.
Attack Path
1. Deliver JS that triggers FTL/DFG tiering
The attacker serves web content whose JavaScript runs a hot loop that allocates and manipulates arrays so the function is tiered up into the DFG/FTL JIT where the array-allocation-sinking phase runs.
2. Shape code so an array is judged non-escaping
Inference: craft control/data flow (e.g. conditional escapes, OSR-exit edges, or phi merges of array allocations) that the escape analysis mis-analyzes, so a genuinely-observable array allocation is sunk.
3. Force materialization on a mishandled path
Inference: drive execution down the path (often an OSR exit or a merge point) where the sunk allocation is materialized with incorrect length, indexing type, or uninitialized backing store.
4. Observe the mis-materialized object
Read or write elements of the array whose in-memory representation no longer matches its logical type/length, yielding out-of-bounds access or corrupted object state.
5. Crash (established) / escalate (background)
The commit establishes only an unexpected WebContent crash. Standard escalation background: an OOB/type-inconsistent array primitive in JSC is the classic starting point for addrof/fakeobj and arbitrary read/write, but nothing in this diff demonstrates that reliability.
Impact Assessment
The advisory rates this medium with the impact limited to an unexpected process crash, and the fix (disabling an optimization by default) is consistent with a JIT-correctness/miscompilation bug rather than a demonstrated weaponized primitive. Inference: soundness bugs in JSC allocation sinking can in principle yield an out-of-bounds or type-inconsistent array, which is the canonical stepping stone toward arbitrary read/write and RCE inside the renderer; however this diff does not establish exploitability beyond a crash. The bug is confined to the WebContent (renderer) process running the JIT, so any escalation would still face the WebContent sandbox before reaching the system.
Audit Directions
Read the allocation-sinking phase directly
Inspect Source/JavaScriptCore/dfg/DFGObjectAllocationSinkingPhase.cpp and any array-specific sinking logic for escape-analysis edge cases; grep for materialize, PhantomNewArray, PhantomCreateActivation, and handling of OSR-exit and phi merges of allocation nodes.
Cross-check other sunk allocation kinds
The same soundness class can affect non-array sunk allocations; grep for Phantom* node kinds and the promoted-heap/materialization code to see whether object, arguments, or activation sinking share the mishandled path.
Audit other default-true optimization flags
Search OptionsList.h for recently-flipped or historically-flipped Normal Bool optimization options (grep useOMGInlining, useArray*, useConcurrent*) to find optimizations disabled as covert security mitigations and re-examine their phases.
Correlate option flip with regressions
Diff the JIT phase files around this commit range and look for follow-up commits re-enabling useArrayAllocationSinking with an actual analysis fix; the real root-cause change reveals the exact violated invariant to search for in sibling phases.
Changed Functions
| Function | File | Change | Note |
|---|---|---|---|
useArrayAllocationSinking (option default) |
Source/JavaScriptCore/runtime/OptionsList.h |
modified | Default value changed from true to false, disabling the array-allocation-sinking JIT optimization by default; the buggy phase code itself is not in this diff. |
Files Changed
Source Files
Source/JavaScriptCore/runtime/OptionsList.h