File size: 2,867 Bytes
131b46b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | ---
license: mit
tags:
- security
- proof-of-concept
- tensorflow-js
- denial-of-service
---
# TensorFlow.js weights-manifest shape DoS PoC
This repository contains a proof-of-concept malicious `.tfjs`-style weights manifest for a
responsibly-disclosed vulnerability in [`tensorflow/tfjs`](https://github.com/tensorflow/tfjs)
(tested at commit `7f5309fef0a47545e34049903dbdae0f97285f7e`), reported via huntr's Model File
Vulnerability program.
## What these files are
- `malicious_manifest.json` β a weights manifest declaring a single weight, `malicious_weight`,
of `dtype: "string"` and `shape: [500000000]` (500 million).
- `weights.bin` β the "backing" weight-data file the manifest points to. It is **completely
empty (0 bytes)** β there is no real weight data behind the declared shape at all.
- `reproduce.js` β loads the manifest using `@tensorflow/tfjs`'s public, officially-documented
`tf.io.weightsLoaderFactory` API (the same pattern shown in that function's own JSDoc example
for loading weights from disk in Node.js without the native `tfjs-node` addon) β no internal or
private functions are used.
## What happens when you run it
```
npm install @tensorflow/tfjs
node reproduce.js
```
The process becomes unresponsive (including a 2-second heartbeat timer in the script itself, which
does not fire while the vulnerable loop is running β the entire Node.js event loop is blocked, not
just the one loading operation) and, after roughly 3.5 minutes, **crashes outright** with a fatal
V8 out-of-memory error (`FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed -
JavaScript heap out of memory`, heap grown past 4 GB) β not merely a temporary freeze. `500000000`
was chosen so the demonstration completes in a few minutes; a real attacker could use an even
larger value (e.g. `999999999999`, still just a single JSON integer) for a longer/guaranteed crash
against a victim with more available memory. See the reporter's full write-up submitted via huntr
for the complete timing data and crash log.
This happens because `getWeightBytelength()` (`tfjs-core/src/io/io_utils.ts`) computes the
declared string-tensor size (`sizeFromShape(shape)`, unbounded, no validation) and loops that many
times over the weight's binary data β with no check that any real data is actually behind the
declared shape, and no early exit when the (in this case entirely empty) backing buffer is
exhausted.
## Scope note
This PoC is provided solely for the purpose of responsible vulnerability disclosure and
reproduction by the `tfjs` maintainers / huntr triage team. It is not intended for any other use.
Running it will make your own Node.js process unresponsive for the duration of the demo β this is
expected and is exactly the behavior being reported; do not run it against a shared or
production process.
|