Medium CVSS 4.3 webkit OOB 🔧 Commit mapped

Overview

Medium
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
DescriptionProcessing maliciously crafted web content may lead to an unexpected process crash
ComponentJSC YARR
Bug ClassOOB
Tracker279780
Fix commit85d061be2854 (WebKit/WebKit)
CWECWE-787 (Out-of-bounds write)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L
CISA KEVNot listed
Creditedan anonymous researcher, Q1IQ (@q1iqF) and P1umer (@p1umer)
Disclosed2024-10-28

Background

YARR
Yet Another Regex Runtime — JavaScriptCore’s regular-expression engine that compiles JS RegExp patterns into an internal representation and bytecode/JIT.
Character class construction
The phase that builds the set of code points/ranges a bracket expression […] matches, including coalescing overlapping ranges and applying set operations.
RegExp 'v' flag (unicodeSets)
An ES2024 flag enabling set notation and string members (\q{…}, intersection/subtraction) in character classes, which introduces multi-code-point ‘strings’ matches.
Case-folding under the 'i' flag
Case-insensitive matching that expands each member to its case-equivalent code points, which can be appended in non-monotonic numeric order.
Sorted-merge precondition
The requirement that set/union/intersection routines receive their inputs pre-sorted so their single-pass index-advancing merge produces correct results.

Root Cause Analysis

The patch is in JavaScriptCore’s YARR regex engine, in CharacterClassConstructor, which builds the internal representation of a regular-expression character class. The change adds std::sort calls in two places: after collecting asciiMatches/unicodeMatches, and after collecting matches/matchesUnicode (alongside utf32Strings), immediately before performOp() and performSetOpWithMatches()/performSetOpWithStrings() are invoked. The added stress test exercises character classes using the ES2024 RegExp ‘v’ flag with ‘strings’ syntax (\q{…} with alternations like \q{\u{0095}|k}) under the case-insensitive ‘i’ flag. The violated invariant is that the set-operation and range-coalescing routines (performOp / performSetOpWithMatches) assume their input match/range vectors are in sorted order: these algorithms merge, intersect, subtract, and coalesce ranges by walking the vectors in monotonically increasing order and comparing/advancing indices. When the ‘v’ flag with case-folding (i flag) produces individual match code points, folding a character such as U+0095 can append case-equivalent code points out of numeric order relative to previously appended ASCII characters (e.g. ‘k’/’s’), leaving asciiMatches/unicodeMatches (and the matches/matchesUnicode vectors) unsorted. Feeding an unsorted vector into a routine that assumes sorted order breaks the merge invariant, producing incorrect index advancement and out-of-order comparisons.

The fix restores the invariant by explicitly sorting all four vectors before the set/coalesce operations run, guaranteeing the monotonic-order precondition. Note: the exact failure inside performOp/performSetOpWithMatches is not shown in this diff (those bodies are not included), so the precise mechanism by which unsorted input leads to the observed crash is an inference from the nature of sorted-merge algorithms and the fact that the fix is purely ‘sort the inputs first.’ What the commit establishes concretely is that the inputs were not guaranteed sorted and that the set/coalesce operations require sorted input.

Key insight
Two set/coalesce routines in YARR character-class construction implicitly required sorted match vectors, but ‘v’-flag string members with case-folding could append code points out of order, so the missing sort broke a merge invariant and led to a crash — an unenforced ordering precondition on data an attacker can shape.

Attack Path

  1. Deliver a crafted RegExp to the JS engine Attacker-controlled web content constructs and compiles a regular expression using the ‘v’ flag with the ‘strings’ character-class syntax (\q{…}) combined with the ‘i’ (ignore-case) flag, e.g. /[\q{\u{0095}|k}]/vi.
  2. Trigger case-folding that emits out-of-order matches During compilation, case-insensitive folding of the string/alternation members appends case-equivalent code points (from U+0095 and from ASCII ‘k’/’s’) into the match/unicode vectors in an order that is not numerically sorted.
  3. Enter the set/coalesce operation with unsorted input CharacterClassConstructor calls performOp()/performSetOpWithMatches() on the unsorted asciiMatches/unicodeMatches (and matches/matchesUnicode) vectors, violating the routine’s sorted-order precondition.
  4. Corrupt index/range traversal The merge-style algorithm advances indices and compares ranges assuming monotonic order; with unsorted data it mis-tracks positions, leading to an inconsistent internal state during character-class construction (inferred to reach an out-of-bounds access or invalid range).
  5. Crash the WebContent process The corrupted traversal results in an unexpected process crash (the CVE’s stated impact) when the malformed character class is compiled.

Impact Assessment

Per the CVE, the realistic outcome is an unexpected process crash triggered by compiling a malformed ‘v’-flag character class — a denial-of-service-grade primitive rather than a demonstrated read/write. Whether the unsorted-input traversal yields an exploitable out-of-bounds access or merely an assertion/abort is not shown by this diff; the fix (sorting the inputs) is consistent with either a controlled crash or a bounded OOB during range coalescing, so any escalation toward memory disclosure/RCE is speculative and not established by the commit. The bug is confined to the WebContent (or any JSC-hosting) process where the attacker’s script runs; there is no cross-process or sandbox-boundary effect from this flaw itself.

Changed Functions

FunctionChangeNotes
CharacterClassConstructor (ASCII/unicode match handler, ~line 234)
Source/JavaScriptCore/yarr/YarrPattern.cpp
modified Added std::sort of asciiMatches and unicodeMatches before performOp(), ensuring the coalesce/set operation receives inputs in the required sorted order.
CharacterClassConstructor (strings/set-op handler, ~line 362)
Source/JavaScriptCore/yarr/YarrPattern.cpp
modified Added std::sort of matches and matchesUnicode before performSetOpWithStrings()/performSetOpWithMatches(), restoring the sorted-input precondition for the 'v'-flag string set operations.

Audit Directions

  • Other match/range vectors feeding YARR set operations
    In YarrPattern.cpp, audit every vector consumed by performOp, performSetOpWithMatches, performSetOpWithStrings, and range-coalescing helpers to confirm each is sorted before use; grep ‘performSetOp’, ‘performOp’, ‘matchesUnicode’, ‘asciiMatches’, ‘coalesce’.
  • Sorted-order assumptions in unicodeSets/'v'-flag handling
    Review all \q{…} string-member and case-folding paths for reliance on numeric ordering; grep ‘utf32Strings’, ‘ignoreCase’, ‘foldCase’, ‘CharacterClassStringSet’, and any binary-search or merge over match arrays.
  • Merge/dedup algorithms that assume pre-sorted input across JSC
    Look for single-pass merge or std::unique-style logic that does not sort first in YARR and adjacent JSC components; grep for ‘std::unique’, ’lower_bound’, ‘binarySearch’, and index-advancing loops (i++/j++) over character-range vectors.

Original Bug Report

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