# TensorFlow.js string weight metadata DoS PoC This repository contains a minimal TensorFlow.js model-file-format PoC for a CPU denial-of-service in `@tensorflow/tfjs` 4.22.0. The malicious model is a valid one-layer Dense LayersModel plus one extra unused weight manifest entry: ```json { "name": "unused_extra_string", "shape": [50000000], "dtype": "string" } ``` The weights file is only 8 bytes. Loading the model with `tf.loadLayersModel()` decodes every weight spec before strict model-weight matching rejects extras. For `dtype: "string"`, `tf.io.decodeWeights()` loops over `sizeFromShape(spec.shape)` while trying to read per-string length headers. With a large shape and truncated/empty string data, the Node.js event loop is tied up until an external watchdog kills the process. ## Reproduce ```bash npm ci npm run repro ``` Expected result: - `control_valid_model`: loads and predicts `7` in about 10 ms. - `numeric_extra_float32_control`: rejects the extra large numeric weight in about 15 ms. - `malicious_extra_string_dos`: does not return before the 3 second watchdog and is killed with `ETIMEDOUT` / `SIGKILL`. For a shorter local demo: ```bash npm run repro:small ``` ## Files - `repro_tfjs_string_weight_dos.js` - standalone reproducer and watchdog. - `models/` - control, numeric-control, and malicious TF.js `model.json` / `weights.bin` files. - `evidence/tfjs-string-weight-dos-repro-2026-06-23-132907011.json` - recorded reproduce run. - `evidence/tfjs-string-weight-timing-2026-06-23-132953595.json` - timing curve showing string weights scale linearly while numeric weights reject immediately. - `source/` - local source excerpts from the installed 4.22.0 package. - `duplicate-check.md` - local, dashboard, and public Huntr duplicate gate notes. - `report.md` - Huntr report body. - `SHA256SUMS` - hashes for all package files. ## Environment - Node.js `v20.20.2` - npm `10.8.2` - `@tensorflow/tfjs` `4.22.0`