Medium CVSS 4 webkit OOB 🔧 Commit mapped

Overview

Medium
Severity
4
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may disclose internal states of the app
ComponentJSC YARR
Bug ClassOOB
Tracker294182
Fix commitd96ab2fa64c6 (WebKit/WebKit) +8/-39
CWECWE-125 (Out-of-bounds read)
CVSS vectorCVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N
CISA KEVNot listed
CreditedHexRabbit (@h3xr4bb1t) from DEVCORE Research Team
Disclosed2025-07-29

Background

YARR JIT
JavaScriptCore’s JIT-compiled regular-expression matcher.
BMP / non-BMP / surrogate pair
Non-BMP code points are encoded as two UTF-16 units (a surrogate pair); reading one advances the index by 2, not 1.
firstCharacterAdditionalReadSize
A register holding how much extra to advance the index after reading a possible surrogate pair on a failed match.
Sentinel latching
The removed scheme used a sentinel value and conditional moves to set the advance once; its state could desynchronize.

Root Cause Analysis

YarrJIT’s Unicode fast path has an optimization (YARR_JIT_UNICODE_CAN_INCREMENT_INDEX_FOR_NON_BMP) that, after reading a non-BMP code point encoded as a surrogate pair, advances the subject index by 2 instead of 1 on a failed match. It implemented this with a register, firstCharacterAdditionalReadSize, initialized to a sentinel (0x4) and then conditionally changed to 0 (BMP) or 1 (non-BMP) using moveConditionallyTest32/addOneConditionally against the sentinel, intended to latch the value on the first read and not change it again. That sentinel-conditional scheme was buggy: under the right sequence the additional-read-size could be left at a wrong value, so the matcher advanced the index by the wrong amount and computed an out-of-bounds subject position, reading characters past the end of the string. Since regexp match results and internal offsets derive from that read, the bug discloses adjacent internal memory (the advisory: ‘may disclose internal states of the app’).

The fix removes the sentinel dance entirely and unconditionally sets firstCharacterAdditionalReadSize to 1 for the non-BMP-optimization case (jit.move(TrustedImm32(1), ...)), deleting the fragile conditional latching in both the fast (tryReadUnicodeCharImpl) and slow (tryReadUnicodeCharSlowImpl) generators.

The restored invariant is that the surrogate-pair index advance is a fixed, correct amount rather than a stateful conditional that could desynchronize.

Key insight
The YARR-JIT surrogate-pair index advance used a fragile sentinel-conditional to set the extra read size, which could be left wrong and push the match index out of bounds, leaking memory; using a fixed advance of 1 removes the desync.

Attack Path

  1. Craft a Unicode regexp Build a /u regexp whose JIT path uses the non-BMP first-character read optimization.
  2. Feed surrogate-pair input Match against a subject with non-BMP characters positioned so the sentinel-conditional additional-read-size is left wrong.
  3. Advance index out of bounds The matcher adds the wrong additional read size and computes a subject position past the string end.
  4. Disclose memory Out-of-bounds character reads leak adjacent internal memory into match results in the WebContent process.

Impact Assessment

An out-of-bounds read in the YARR JIT’s non-BMP index-advance logic, reachable from a crafted Unicode regexp in the WebContent process. Per the advisory it discloses internal application memory (an info-leak primitive useful for defeating ASLR), rather than a crash. Confined to WebContent; rated medium.

Changed Functions

FunctionChangeNotes
tryReadUnicodeCharImpl (YarrJIT)
Source/JavaScriptCore/yarr/YarrJIT.cpp
modified Replaces the sentinel-based conditional latching of firstCharacterAdditionalReadSize with an unconditional move of 1 for the non-BMP optimization, removing the buggy stateful advance.
tryReadUnicodeCharSlowImpl (YarrJIT)
Source/JavaScriptCore/yarr/YarrJIT.cpp
modified Removes the matching sentinel-conditional code in the slow path and the additionalReadSizeSentinel constant.

Files Changed

  • Source/JavaScriptCore/yarr/YarrJIT.cpp

Audit Directions

  • Other conditional index advances
    grep YarrJIT for moveConditionallyTest/addOneConditionally on index/read-size registers where a stateful sentinel could desync.
  • Non-BMP / surrogate handling
    Audit surrogate-pair read paths (backreferences, character classes) for correct fixed index advances and bounds checks.
  • OOB read surfaces
    Review how match offsets derived from JIT reads are bounds-checked against the subject length before use.

Original Bug Report

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