CVE-2026-102992: piscina: Prototype-pollution gadget in ThreadPool.options allows RCE via execArgv / loadBalancer / env

Published Sep 30, 2026
·
Updated

Summary

A 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.

Details

In src/index.ts the ThreadPool constructor builds the resolved options object as a plain object:

ts this.options = { ...kDefaultOptions, ...options, filename, maxQueue: 0 }

Because 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.

The 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.

This 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.

PoC

js import { resolve } from 'node:path' import Piscina from 'piscina'

Object.prototype.execArgv = ['--require', '/tmp/attacker.js']

const pool = new Piscina({ filename: resolve(import.meta.dirname, 'worker.js'), minThreads: 1, maxThreads: 1, })

await pool.run(1)

/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.

Impact

- Remote Code Execution: via execArgv (arbitrary --require module preloaded in every worker on spawn). - Arbitrary code execution in the main thread: via loadBalancer, an attacker-supplied function that is called during task scheduling. - Environment/CLI option injection: via env, which is passed to each worker constructor. - Denial of Service / unexpected behavior: via other reachable options such as workerData, resourceLimits, niceIncrement, closeTimeout, recordTiming, etc.

Anyone using Piscina in an application where Object.prototype can be polluted (e.g. through a dependency with a prototype-pollution vulnerability) is impacted.

Other sources

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.

— NVD

piscina: Prototype-pollution gadget in ThreadPool.options allows RCE via execArgv / loadBalancer / env

— Microsoft

Affected Software

4 affected componentsFixes available
npm/piscina<4.9.4, >=5.0.0<5.3.2, >=6.0.0-rc.0<6.0.0-rc.5
npm/piscina>=6.0.0-rc.1<6.0.0-rc.5
6.0.0-rc.5
npm/piscina<4.9.4
4.9.4
npm/piscina>=5.0.0<5.3.2
5.3.2

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/piscina to a version that resolves this vulnerability.

    Fixed in 6.0.0-rc.5
  2. Upgrade

    Upgrade npm/piscina to a version that resolves this vulnerability.

    Fixed in 4.9.4
  3. Upgrade

    Upgrade npm/piscina to a version that resolves this vulnerability.

    Fixed in 5.3.2
  4. Upgrade

    Upgrade piscina to a version that resolves this vulnerability.

    Fixed in 4.9.4
  5. Upgrade

    Upgrade piscina to a version that resolves this vulnerability.

    Fixed in 5.3.2
  6. Upgrade

    Upgrade piscina to a version that resolves this vulnerability.

    Fixed in 6.0.0-rc.5

Event History

Sep 30, 2026
CVE Published
via MITRE·07:50 PM
Data Sourced
via MITRE·07:50 PM
DescriptionWeakness
Data Sourced
via NVD·08:17 PM
DescriptionSeverityWeakness
Oct 1, 2026
Advisory Published
via GitHub·03:03 PM
Data Sourced
via GitHub·03:03 PM
DescriptionWeaknessAffected Software
Oct 3, 2026
Data Sourced
via Microsoft·08:39 AM
DescriptionSeverityWeakness

Frequently Asked Questions

1

Which deployments are exposed to exploitation?

Exposure requires an application using a vulnerable Piscina version and a separate prototype-pollution primitive. The issue affects versions before 4.9.4, 5.3.2, and 6.0.0-rc.5.

2

What attacker-controlled options can lead to code execution or other impact?

Inherited execArgv values can be passed to the Node.js Worker constructor and preload attacker-controlled code in worker threads. An inherited loadBalancer function can execute during task scheduling, while inherited env values can modify worker environments.

3

Is Piscina alone sufficient for exploitation?

No. The described attack depends on a separate prototype-pollution primitive that lets an attacker provide inherited values for ThreadPool.options.

4

What remediation is available?

Upgrade Piscina to 4.9.4, 5.3.2, or 6.0.0-rc.5, as appropriate for the release line in use.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203