diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js index 748f14a283f05f..24894624487ea7 100644 --- a/lib/internal/child_process.js +++ b/lib/internal/child_process.js @@ -427,6 +427,13 @@ ChildProcess.prototype.spawn = function(options) { for (i = 0; i < stdio.length; i++) { const stream = stdio[i]; + // Never trust the user input/runtime + // Refs: https://github.com/nodejs/node/issues/55932 + if (!stream) { + process.nextTick(onErrorNT, this, UV_EINVAL); + return UV_EINVAL; + } + if (stream.type === 'ignore') continue; if (stream.ipc) { diff --git a/src/process_wrap.cc b/src/process_wrap.cc index 27a294eb384960..8ae3cc4c00518f 100644 --- a/src/process_wrap.cc +++ b/src/process_wrap.cc @@ -26,6 +26,7 @@ #include "stream_wrap.h" #include "util-inl.h" +#include #include #include #include @@ -122,6 +123,16 @@ class ProcessWrap : public HandleWrap { for (uint32_t i = 0; i < len; i++) { Local stdio = stdios->Get(context, i).ToLocalChecked().As(); + + // Never trust the user. + // Refs: https://github.com/nodejs/node/issues/55932 + if (!stdio->IsObject()) { + stdio = Object::New(env->isolate()); + stdio->Set(context, + env->type_string(), + env->ignore_string()).FromJust(); + } + Local type = stdio->Get(context, env->type_string()).ToLocalChecked(); diff --git a/test/parallel/test-child-process-muted-array-proto.js b/test/parallel/test-child-process-muted-array-proto.js new file mode 100644 index 00000000000000..f10618e8c8abee --- /dev/null +++ b/test/parallel/test-child-process-muted-array-proto.js @@ -0,0 +1,28 @@ +'use strict'; + +const common = require('../common'); +const assert = require('node:assert'); +const { spawn } = require('node:child_process'); + +// The UNIX version of this test is enough. +if (common.isWindows) { + common.skip('This test is enough for Unix-like systems'); + return; +} + +// Refs: https://github.com/nodejs/node/issues/55932 +Object.defineProperty(Array.prototype, '0', { + set() { + console.log(123); + }, + get() { + return 123; + } +}, { configurable: true, writable: true }); + +const cp = spawn('ls'); + +// Can't use common.mustCall() here because array prototype is mutated. +cp.on('error', (err) => { + assert.strictEqual(err.code, 'EINVAL'); +});