{"id":"GHSA-67c8-pqhq-4rmx","revision":null,"records":[{"revision":"b07c42bb9ea344ba80a6b44835b0f85a","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-102992","aliases":[],"title":"piscina: Prototype-pollution gadget in ThreadPool.options allows RCE via execArgv / loadBalancer / env","description":"piscina is a node.js worker pool implementation. Prior to 4.9.4, 5.3.2, and 6.0.0-rc.5, Piscina stores ThreadPool.options in src/index.ts as a plain object that inherits from Object.prototype. Applications with a separate prototype-pollution primitive can therefore supply inherited values for security-sensitive options that do not have own defaults. An inherited execArgv value is passed to the Node.js Worker constructor and can preload attacker-controlled code in worker threads, an inherited loadBalancer function can execute during task scheduling, and inherited env values can alter worker environments. This issue is fixed in versions 4.9.4, 5.3.2, and 6.0.0-rc.5.","state":0,"publishedAt":"2026-09-30T19:50:18.036+00:00","modifiedAt":"2026-09-30T20:47:49.562+00:00","affected":[{"ecosystem":"Vendor product","name":"piscina","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"piscinajs\",\n                    \"product\": \"piscina\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 4.9.4\",\n                            \"status\": \"affected\"\n                        },\n                        {\n                            \"version\": \">= 5.0.0, < 5.3.2\",\n                            \"status\": \"affected\"\n                        },\n                        {\n                            \"version\": \">= 6.0.0-rc.1, < 6.0.0-rc.5\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 4.0","vector":"CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","score":9.2,"severity":"CRITICAL"}],"references":["https://github.com/piscinajs/piscina/security/advisories/GHSA-67c8-pqhq-4rmx","https://github.com/piscinajs/piscina/commit/0cb12fca37f526065b072592afe954574dcc656f","https://github.com/piscinajs/piscina/commit/2f69f67159a0e48b38fd61fa4a91c2fdc19fff72","https://github.com/piscinajs/piscina/commit/5be7bbb19e3787bb698862cd516121a578d690f7","https://github.com/piscinajs/piscina/commit/bebbda255c2981cecddd36b171b94be2fd41c9a6","https://github.com/piscinajs/piscina/releases/tag/v4.9.4","https://github.com/piscinajs/piscina/releases/tag/v5.3.2","https://github.com/piscinajs/piscina/releases/tag/v6.0.0-rc.5"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-102992","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-102992","identifiers":["CVE-2026-102992"]},"retained":false,"historicalAffected":[]},{"revision":"43de3bcefcfb438c99ac85aa10358911","observedAt":"2026-11-11T05:29:45.685+00:00","statement":{"source":"euvd","id":"EUVD-2026-90364","aliases":["CVE-2026-102992","GHSA-67c8-pqhq-4rmx"],"title":"piscina is a node.js worker pool implementation. Prior to 4.9.4, 5.3.2, and 6.0.0-rc.5, Piscina stores ThreadPool.options in src/index.ts as a plain object that inherits from Object.prototype. Applications with a separate prototype-pollutio…","description":"piscina is a node.js worker pool implementation. Prior to 4.9.4, 5.3.2, and 6.0.0-rc.5, Piscina stores ThreadPool.options in src/index.ts as a plain object that inherits from Object.prototype. Applications with a separate prototype-pollution primitive can therefore supply inherited values for security-sensitive options that do not have own defaults. An inherited execArgv value is passed to the Node.js Worker constructor and can preload attacker-controlled code in worker threads, an inherited loadBalancer function can execute during task scheduling, and inherited env values can alter worker environments. This issue is fixed in versions 4.9.4, 5.3.2, and 6.0.0-rc.5.","state":0,"publishedAt":null,"modifiedAt":null,"affected":[],"metrics":[{"system":"EUVD CVSS 4.0","vector":"CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","score":9.2,"severity":null}],"references":["https://github.com/piscinajs/piscina/security/advisories/GHSA-67c8-pqhq-4rmx","https://github.com/piscinajs/piscina/commit/0cb12fca37f526065b072592afe954574dcc656f","https://github.com/piscinajs/piscina/commit/2f69f67159a0e48b38fd61fa4a91c2fdc19fff72","https://github.com/piscinajs/piscina/commit/5be7bbb19e3787bb698862cd516121a578d690f7","https://github.com/piscinajs/piscina/commit/bebbda255c2981cecddd36b171b94be2fd41c9a6","https://github.com/piscinajs/piscina/releases/tag/v4.9.4","https://github.com/piscinajs/piscina/releases/tag/v5.3.2","https://github.com/piscinajs/piscina/releases/tag/v6.0.0-rc.5"],"sourceUrl":"https://euvd.enisa.europa.eu/vulnerability/EUVD-2026-90364","license":"ENISA EUVD · source terms and attribution apply","enrichment":{"sourceStatus":null,"weaknesses":[],"productCriteria":[],"sourceDates":{"datePublished":"Sep 30, 2026, 7:50:18 PM","dateUpdated":"Sep 30, 2026, 8:47:49 PM"},"relatedAdvisories":[{"id":"msrc_CVE-2026-102992","title":"piscina: Prototype-pollution gadget in ThreadPool.options allows RCE via execArgv / loadBalancer / env","vulnerabilityIds":["CVE-2026-102992"]}],"note":"EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON."},"key":"euvd:EUVD-2026-90364","identifiers":["EUVD-2026-90364","CVE-2026-102992","GHSA-67c8-pqhq-4rmx"]},"retained":false,"historicalAffected":[]},{"revision":"ff58106457364618b3c0d8108fab4c00","observedAt":"2026-10-25T04:17:29.458+00:00","statement":{"source":"nvd","id":"CVE-2026-102992","aliases":[],"title":"piscina is a node.js worker pool implementation. Prior to 4.9.4, 5.3.2, and 6.0.0-rc.5, Piscina stores ThreadPool.options in src/index.ts as a plain object that inherits from Object.prototype. Applications with a separate prototype-pollutio…","description":"piscina is a node.js worker pool implementation. Prior to 4.9.4, 5.3.2, and 6.0.0-rc.5, Piscina stores ThreadPool.options in src/index.ts as a plain object that inherits from Object.prototype. Applications with a separate prototype-pollution primitive can therefore supply inherited values for security-sensitive options that do not have own defaults. An inherited execArgv value is passed to the Node.js Worker constructor and can preload attacker-controlled code in worker threads, an inherited loadBalancer function can execute during task scheduling, and inherited env values can alter worker environments. This issue is fixed in versions 4.9.4, 5.3.2, and 6.0.0-rc.5.","state":0,"publishedAt":"2026-09-30T20:17:27.08+00:00","modifiedAt":"2026-09-30T21:17:06.45+00:00","affected":[],"metrics":[{"system":"CVSS 4.0 · security-advisories@github.com · Secondary","vector":"CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","score":9.2,"severity":"CRITICAL"}],"references":["https://github.com/piscinajs/piscina/commit/0cb12fca37f526065b072592afe954574dcc656f","https://github.com/piscinajs/piscina/commit/2f69f67159a0e48b38fd61fa4a91c2fdc19fff72","https://github.com/piscinajs/piscina/commit/5be7bbb19e3787bb698862cd516121a578d690f7","https://github.com/piscinajs/piscina/commit/bebbda255c2981cecddd36b171b94be2fd41c9a6","https://github.com/piscinajs/piscina/releases/tag/v4.9.4","https://github.com/piscinajs/piscina/releases/tag/v5.3.2","https://github.com/piscinajs/piscina/releases/tag/v6.0.0-rc.5","https://github.com/piscinajs/piscina/security/advisories/GHSA-67c8-pqhq-4rmx"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-102992","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-1321"],"productCriteria":[],"sourceDates":{"published":"2026-09-30T20:17:27.080","lastModified":"2026-09-30T21:17:06.450"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-102992","identifiers":["CVE-2026-102992"]},"retained":false,"historicalAffected":[]},{"revision":"2e25e7e0b44041b38b32d06450871160","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-67c8-pqhq-4rmx","aliases":["CVE-2026-102992"],"title":"piscina: Prototype-pollution gadget in ThreadPool.options allows RCE via execArgv / loadBalancer / env","description":"### Summary\n\nA prototype-pollution gadget in `ThreadPool.options` allows an attacker who can pollute `Object.prototype` to execute arbitrary code in Piscina worker threads, invoke arbitrary functions during task scheduling, or inject environment variables into workers. The root cause is that `ThreadPool.options` is created as a plain object inheriting from `Object.prototype`, so any option without an explicit default in `kDefaultOptions` can be supplied via the prototype chain.\n\n### Details\n\nIn `src/index.ts` the `ThreadPool` constructor builds the resolved options object as a plain object:\n\n```ts\nthis.options = { ...kDefaultOptions, ...options, filename, maxQueue: 0 }\n```\n\nBecause this object has `Object.prototype` as its prototype, reads for properties that are not own properties of the object and are not present in `kDefaultOptions` fall back to `Object.prototype`. This means a prototype-pollution primitive (e.g. from a vulnerable `merge()` or `JSON.parse` merge elsewhere in the application) can inject values for `execArgv`, `env`, `loadBalancer`, `argv`, `workerData`, `resourceLimits`, `niceIncrement`, `closeTimeout`, `recordTiming`, `stricterFIFO`, `workerHistogram`, and `trackUnmanagedFds`.\n\nThe most serious gadget is `execArgv`, which is passed directly to `new Worker(..., { execArgv })`. An attacker can set `Object.prototype.execArgv = ['--require', '/tmp/attacker.js']`, causing every worker to preload and execute the attacker-controlled module on startup.\n\nThis issue survived the fix for **GHSA-x9g3-xrwr-cwfg / CVE-2026-55388** (\"Prototype Pollution Gadget → RCE via inherited options.filename\"). That advisory hardened the `Piscina` constructor's `filename` read and `run()`'s `filename`/`name` reads, but `ThreadPool.options` itself was not created with a null prototype. The same class of attack is therefore still possible against any option without an explicit default in `kDefaultOptions`.\n\n### PoC\n\n```js\nimport { resolve } from 'node:path'\nimport Piscina from 'piscina'\n\nObject.prototype.execArgv = ['--require', '/tmp/attacker.js']\n\nconst pool = new Piscina({\n  filename: resolve(import.meta.dirname, 'worker.js'),\n  minThreads: 1,\n  maxThreads: 1,\n})\n\nawait pool.run(1)\n```\n\n`/tmp/attacker.js` is executed in the worker on startup. A full reproduction repository with `execArgv`, `loadBalancer`, and `env` vectors is available at https://github.com/Fcmam5/piscina-pp-poc.\n\n### Impact\n\n- **Remote Code Execution**: via `execArgv` (arbitrary `--require` module preloaded in every worker on spawn).\n- **Arbitrary code execution in the main thread**: via `loadBalancer`, an attacker-supplied function that is called during task scheduling.\n- **Environment/CLI option injection**: via `env`, which is passed to each worker constructor.\n- **Denial of Service / unexpected behavior**: via other reachable options such as `workerData`, `resourceLimits`, `niceIncrement`, `closeTimeout`, `recordTiming`, etc.\n\nAnyone using Piscina in an application where `Object.prototype` can be polluted (e.g. through a dependency with a prototype-pollution vulnerability) is impacted.","state":0,"publishedAt":"2026-10-01T15:03:33+00:00","modifiedAt":"2026-10-01T15:15:09.1988621+00:00","affected":[{"ecosystem":"npm","name":"piscina","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"5.0.0"},{"kind":"fixed","version":"5.3.2"}]}],"versions":[],"rawVersionEvidence":null},{"ecosystem":"npm","name":"piscina","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"4.9.4"}]}],"versions":[],"rawVersionEvidence":null},{"ecosystem":"npm","name":"piscina","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"6.0.0-rc.1"},{"kind":"fixed","version":"6.0.0-rc.5"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V4","vector":"CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"CRITICAL"}],"references":["https://github.com/piscinajs/piscina/security/advisories/GHSA-67c8-pqhq-4rmx","https://nvd.nist.gov/vuln/detail/CVE-2026-102992","https://github.com/piscinajs/piscina/commit/0cb12fca37f526065b072592afe954574dcc656f","https://github.com/piscinajs/piscina/commit/2f69f67159a0e48b38fd61fa4a91c2fdc19fff72","https://github.com/piscinajs/piscina/commit/5be7bbb19e3787bb698862cd516121a578d690f7","https://github.com/piscinajs/piscina/commit/bebbda255c2981cecddd36b171b94be2fd41c9a6","https://github.com/piscinajs/piscina","https://github.com/piscinajs/piscina/releases/tag/v4.9.4","https://github.com/piscinajs/piscina/releases/tag/v5.3.2","https://github.com/piscinajs/piscina/releases/tag/v6.0.0-rc.5"],"sourceUrl":"https://github.com/advisories/GHSA-67c8-pqhq-4rmx","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-67c8-pqhq-4rmx","identifiers":["GHSA-67c8-pqhq-4rmx","CVE-2026-102992"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-11-12T01:04:03.8350163+00:00","complete":true,"records":1779,"lastAttemptAt":"2026-11-12T01:04:03.8350163+00:00","lastSuccessAt":"2026-11-12T01:04:03.9938616+00:00","error":null,"lastVerifiedAt":"2026-11-12T01:04:03.9938674+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-64752486c567b55b31fb0d7225f5222bcd0019564ac0ac5f0649e242c7b19299-8739c76e681f900923b900c9df0ef75cf421d39cabb54650c4b9ad19b6a76d85","complete":true,"records":424534,"lastAttemptAt":"2026-11-12T01:04:03.0430554+00:00","lastSuccessAt":"2026-11-12T01:04:03.0392424+00:00","error":null,"lastVerifiedAt":"2026-11-12T01:04:03.0430554+00:00","snapshotPublishedAt":"2026-11-12T00:38:29+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-8523375eb3d641bbb0aae62484fb0fa3","complete":false,"records":13760,"lastAttemptAt":"2026-11-12T01:07:17.0110711+00:00","lastSuccessAt":"2026-11-12T01:07:17.0825169+00:00","error":null,"lastVerifiedAt":"2026-11-12T01:07:17.0825169+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-11-12T01:04:03.8350163+00:00","complete":true,"records":1097,"lastAttemptAt":"2026-11-12T01:04:03.8350163+00:00","lastSuccessAt":"2026-11-12T01:04:03.9946093+00:00","error":null,"lastVerifiedAt":"2026-11-12T01:04:03.9946097+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-edde915f937c494687954d1458194597","complete":true,"records":13760,"lastAttemptAt":"2026-11-12T01:04:54.1042073+00:00","lastSuccessAt":"2026-11-12T01:04:54.101+00:00","error":null,"lastVerifiedAt":"2026-11-12T01:04:54.101+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13813,"expectedIdentifiers":13813,"failedIdentifiers":0},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-3562b6c78fd1bd0f0b55daf66a0926ae24f65e462df7f6d928caad458fc696bf","complete":true,"records":9947,"lastAttemptAt":"2026-11-12T01:04:03.677751+00:00","lastSuccessAt":"2026-11-11T04:27:43.6877707+00:00","error":null,"lastVerifiedAt":"2026-11-12T01:04:03.677751+00:00","snapshotPublishedAt":"2026-11-11T03:32:46+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-456002455e0ab94bb92c95476d4e6d175c104cd594749982afd96c893728ecbc","complete":true,"records":2010,"lastAttemptAt":"2026-11-12T01:04:03.0997578+00:00","lastSuccessAt":"2026-11-11T02:36:58.1276999+00:00","error":null,"lastVerifiedAt":"2026-11-12T01:04:03.0997578+00:00","snapshotPublishedAt":"2026-11-11T01:17:51+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-baa8362b4daf9e5f39d5563775a55935e7b442c0735d33274a921579ce4a0d66","complete":true,"records":3093,"lastAttemptAt":"2026-11-12T01:04:03.6923394+00:00","lastSuccessAt":"2026-11-11T13:00:02.5446881+00:00","error":null,"lastVerifiedAt":"2026-11-12T01:04:03.6923394+00:00","snapshotPublishedAt":"2026-11-11T12:47:47+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-685fe7fb2b690656c910a1ea42a9d294e8353311ac8ecfa691a9b0ff1b328804","complete":true,"records":231695,"lastAttemptAt":"2026-11-12T01:04:03.5701135+00:00","lastSuccessAt":"2026-11-11T21:58:47.7265713+00:00","error":null,"lastVerifiedAt":"2026-11-12T01:04:03.5701135+00:00","snapshotPublishedAt":"2026-11-11T21:48:35+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null,"failedIdentifiers":null}]}