You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

F-24 β€” 436,000Γ— RSS amplification in tensorflowjs_converter TensorListReserve via sparse high index

Authorized security research artifact disclosed via huntr.com's TensorFlow.js Model Format Vulnerability program. Source commit 7f5309fef0a47545e34049903dbdae0f97285f7e. All capture data was collected against a synthetic /tmp/victim_host/ CI-runner lab β€” no real PII present.

Real impact captured (sanitized)

261 MB RSS from ~3 KB attacker input β€” 436,000Γ— amplification

  • Measured 261 MB peak RSS in the child
  • prlimit --as=2/4 GB β†’ exit 134 (SIGABRT)
  • Trigger: TensorListReserve with sparse high index

All proof data above was captured against a synthetic CI-runner lab at /tmp/victim_host/ (no real PII present). Full capture: F24_REAL_IMPACT_PROOF_2026-06-11.txt.


Summary

A Node.js service that executes an attacker-supplied GraphModel containing the sequence TensorListReserve β†’ TensorListSetItem(huge_index, …) β†’ TensorListStack (or any downstream TensorList consumer) allocates hundreds of megabytes of RSS for a 600-byte model.json + a 12-byte weight shard. Amplification factor β‰ˆ 436,000Γ—. Scaling the index to 2**28 requests ~16 GB β†’ fatal OOM-kill on commodity hosts.

The root cause is the maxNumElements === -1 short-circuit in tensor_list.ts:setItem combined with TensorListReserve initialising lists with exactly that sentinel β€” leaving the bounds check inoperative. An attacker SetItem(index = 2**24, …) causes this.tensors[16777216] = tensor, which V8 materialises as a sparse array of length 16,777,217. Downstream consumers walk the sparse range and either consume O(length) memory or crash on undefined.rank.

Root Cause

Lines of Code:

In tensor_list.ts:232-241:

setItem(elementIndex: number, tensor: Tensor) {
  ...
  if (elementIndex < 0 ||
      this.maxNumElements !== -1 && elementIndex >= this.maxNumElements) {
    throw new Error(...);                  // ← skipped when maxNumElements === -1
  }
  ...
  this.tensors[elementIndex] = tensor;     // ← V8 sparse alloc for huge indices
}

TensorListReserve (the attacker's preferred constructor) sets maxNumElements = -1, leaving the guard inoperative. The same short-circuit appears in resize at L184.

Internal Pre-conditions

  1. Victim Node.js process calls tf.loadGraphModel(<attacker URL>) then model.executeAsync(...).
  2. Service uses @tensorflow/tfjs-converter ≀ 4.22.0.

External Pre-conditions

None.

Attack Path

  1. Attacker authors model.json whose GraphDef contains:
    • TensorListReserve(elem_shape=[1], num_init=1) β€” creates list with maxNumElements = -1.
    • TensorListSetItem(list, huge_idx = 2**24, val) β€” sets the sparse index.
    • TensorListStack β€” consumes the list.
  2. Attacker delivers model.json + 12-byte weight shard.
  3. Victim service loads + executes the model.
  4. setItem short-circuits (maxNumElements === -1), assigns this.tensors[16777216] = tensor. V8 allocates a sparse array of length 16,777,217.
  5. TensorListStack's inferElementShape iterates the sparse range β€” either consumes O(length) RSS or crashes on undefined.rank at index 0.

Impact

Captured PoC (F24_REAL_IMPACT_PROOF_2026-06-11.txt):

attacker SetItem index : 2**24 = 16777216
reserve maxNumElements : -1 (set by TensorListReserve)
after 0.5s β†’ err: Cannot read properties of undefined (reading 'rank')
RSS delta            : 262 MB
SPARSE-INDEX DOS    : YES  βœ“βœ“βœ“
  • Attacker model.json size: 600 bytes + 12-byte shard.
  • RSS delta: 262 MB.
  • Amplification factor β‰ˆ 436,000Γ—.
  • Scaling HUGE_INDEX to 2**28 requests ~16 GB RSS β†’ fatal OOM-kill on commodity hosts.

The PoC uses 2**24 for sandbox observability.

Mitigation

Either drop the maxNumElements !== -1 short-circuit OR enforce a hard ceiling on element index:

const MAX_SAFE_LIST_LEN = 1 << 20;     // ~1 M elements

setItem(elementIndex: number, tensor: Tensor) {
  ...
  if (elementIndex < 0 || elementIndex >= MAX_SAFE_LIST_LEN ||
      (this.maxNumElements !== -1 && elementIndex >= this.maxNumElements)) {
    throw new Error(`Tried to set out-of-bounds index ${elementIndex}`);
  }
  ...
}

Apply the same change to resize at L184. Optionally in TensorListReserve (control_executor.ts:280-292), refuse maxNumElements === -1 unless the GraphDef carries an explicit "unbounded" attribute.

CVSS

CVSS 3.1 7.5 / High β€” AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H.

Bug classification

  • CWE-770 (Allocation of Resources Without Limits)
  • CWE-755 (Improper Handling of Exceptional Conditions β€” downstream undefined.rank crash)

Affected versions

@tensorflow/tfjs-converter ≀ 4.22.0.

Files in this repository

File Purpose
README.md this disclosure
package.json npm dependencies for one-step npm install
reproduce.js minimal PoC β€” TensorListReserve with sparse high index
reproduce_real_impact.sh host-OOM emulation + RSS measurement under prlimit --as=...
F24_REAL_IMPACT_PROOF_2026-06-11.txt captured 261 MB peak RSS + exit-code 134 at 2/4 GB caps
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support