Piscina Prototype-Pollution Gadget Resurfaces via ThreadPool.options, Enabling RCE (CVE-2026-102992)
What happened
A new GitHub Security Advisory (GHSA-67c8-pqhq-4rmx, tracked as CVE-2026-102992) discloses that the Node.js worker-thread pool library piscina builds its internal ThreadPool.options as a plain object inheriting from Object.prototype. Any option not given an explicit default in kDefaultOptions — including execArgv, loadBalancer, env, argv, workerData, and several others — is read through the prototype chain. If an attacker can pollute Object.prototype (for example via a separate prototype-pollution bug elsewhere in the application's dependency tree), they can inject values for these options into every Piscina pool in the process.
Per the advisory, this is a regression of an earlier fix: GHSA-x9g3-xrwr-cwfg / CVE-2026-55388 hardened specific filename/name reads in the Piscina constructor and run(), but did not give ThreadPool.options itself a null prototype, leaving the broader class of gadget intact. A public proof-of-concept repository is referenced in the advisory, and the exploit status is listed as PoC-public.
Why it matters for defenders
The most severe gadget is execArgv: polluting Object.prototype.execArgv with a value like ['--require', '/tmp/attacker.js'] causes every subsequently spawned worker thread to preload and execute attacker-controlled code on startup — remote code execution with no direct exploitation of Piscina itself required beyond the prototype-pollution primitive. loadBalancer can similarly be hijacked to execute an attacker-supplied function in the main thread during task scheduling, and env allows injecting arbitrary environment variables into workers. Any application that uses piscina for worker-pool task execution and has any other dependency capable of polluting Object.prototype (a startlingly common bug class in JS merge/clone/JSON-merge utilities) is potentially exposed, even though Piscina is not itself the source of the pollution primitive.
What defenders should watch for
- Inventory whether
piscinais in use (directly or transitively) and check the installed version against the fixed release once published by the maintainers. - Audit other dependencies for known or latent prototype-pollution issues — this advisory is a reminder that a pollution bug anywhere in the dependency graph can be weaponized against unrelated libraries that trust
Object.prototype-derived option objects. - At a high level, hunt for unexpected
--require/-rflags or unfamiliar modules being loaded by Node worker threads, and for worker processes spawning with environment variables or CLI arguments that don't match application configuration. - As a mitigation pattern, favor libraries and internal code that build options objects with a null prototype (
Object.create(null)) or that explicitly validate/allowlist option keys rather than spreading untrusted objects into defaults. - Consider runtime hardening such as freezing
Object.prototype(Object.freeze(Object.prototype)) where application behavior permits it, as a defense-in-depth measure against this entire bug class.
Developing intel
This is a same-day advisory and the information here reflects only what has been disclosed so far; a fixed version and further remediation guidance may follow. No detection rule accompanies this note. For full technical details and updates, see the original advisory: GHSA-67c8-pqhq-4rmx.