Medium CVSS 4.3 webkit Type Confusion 🔧 Commit mapped

Overview

Medium
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to an unexpected Safari crash
ComponentJSC DFG
Bug ClassType Confusion
Tracker317611
Fix commit03a07e420089 (WebKit/WebKit) +118/-16
CWECWE-703
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L
CISA KEVNot listed
CreditedOpenAI Codex Security - Amy Burnett
Disclosed2026-08-17

Background

Integer Range Optimization (IRO)
A DFG phase that proves integer value ranges to eliminate redundant overflow/bounds checks.
Relationship / range proof
IRO derives a node’s range from relationships to other nodes; those other nodes’ computations underpin the proof.
NodeMustGenerate / DCE
A flag that forces a node to be kept; without it dead-code elimination can remove a producer whose result an eliminated check silently depended on.

Root Cause Analysis

This fixes an unsafe check elimination in JavaScriptCore’s DFG Integer Range Optimization (IRO) phase: it removed overflow/bounds checks based on a proven integer range but let the nodes that PROVED that range be deleted, so the runtime condition IRO relied on could vanish. IRO’s rangeFor(node) computes a [min, max] range for a node by intersecting the Relationships known about it, and IRO uses that range to, for example, convert a checked arithmetic op to Arith::Unchecked.

Pre-patch, rangeFor returned only the numeric bounds and did not track WHICH relationship established each bound; the producer nodes behind those relationships were not kept alive. A later phase (dead-code elimination) could then remove those producer nodes because nothing referenced them, even though IRO had already dropped a check that depended on the values they compute — so the unchecked op runs without the guarantee the removed producers provided, allowing the very integer overflow / out-of-bounds the check was meant to catch.

The fix augments rangeFor to return RangeBound { value, proof } where proof points to the Relationship that set each bound, and adds pinRangeBounds/pinRangeBoundProof which mark the upstream left/right nodes of those proof relationships with NodeMustGenerate before a checked op is flipped to unchecked, so DCE keeps the range-proving producers alive.

The restored invariant is that when IRO removes a check based on a range proof, the computations establishing that proof are pinned and cannot be eliminated. (A FIXME notes NodeMustGenerate is a conservative, sticky pin pending reference-counted effect edges.)

Key insight
IRO eliminated checks based on a proven range but did not keep alive the nodes that proved the range, so DCE could delete them and leave an unchecked op without its guarantee; pinning the proof producers with NodeMustGenerate preserves the runtime condition.

Attack Path

  1. Reach the DFG IRO phase Run JS whose arithmetic/array indexing the DFG optimizes with Integer Range Optimization.
  2. Prove a range, drop a check IRO proves a value’s range from relationships and converts a checked op to Arith::Unchecked (removing the overflow/bounds check).
  3. Delete the proof producers DCE removes the now-unreferenced nodes that established the range, since IRO didn’t pin them.
  4. Overflow / out-of-bounds The unchecked op runs without the guaranteeing computation, producing the integer overflow / OOB the check prevented — memory corruption in WebContent.

Impact Assessment

A JIT miscompilation in the WebContent process: IRO could remove an overflow/bounds check while DCE deleted the computation that justified removal, so the unchecked operation overflows or reads out of bounds. The advisory rates it a crash; removed-check bugs in the DFG are strong routes to controlled OOB and memory corruption.

Changed Functions

FunctionChangeNotes
IntegerRangeOptimization rangeFor / RangeBound
Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp
modified Returns RangeBound { value, proof } tracking the Relationship that set each min/max bound instead of bare int32 bounds.
pinRangeBounds / pinRangeBoundProof
Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp
added Marks the upstream left/right nodes of a bound's proof relationship with NodeMustGenerate before flipping a checked op to unchecked, so DCE cannot remove the range-proving producers.

Files Changed

  • JSTests/stress/arith-abs-checked-input-range.js
  • Source/JavaScriptCore/dfg/DFGIntegerRangeOptimizationPhase.cpp

Audit Directions

  • Range-proof lifetime
    Audit IRO (and other range/relationship-based check-removal) for cases that drop a check based on a proof whose producer nodes are not pinned or otherwise kept alive.
  • Check-to-unchecked conversions
    Grep the DFG for Arith::Unchecked / check-removal transforms and verify the values justifying them survive later DCE.

Original Bug Report

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