--- 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.