diff --git a/lib/child_process.js b/lib/child_process.js index 6ce21363e1ee6a..6cdcb701ce4fa0 100644 --- a/lib/child_process.js +++ b/lib/child_process.js @@ -39,6 +39,7 @@ const { ObjectPrototypeHasOwnProperty, RegExpPrototypeExec, SafeSet, + StringPrototypeIncludes, StringPrototypeSlice, StringPrototypeToUpperCase, } = primordials; @@ -734,6 +735,7 @@ function abortChildProcess(child, killSignal) { */ function spawn(file, args, options) { options = normalizeSpawnArguments(file, args, options); + validateArgumentsNullCheck(options.args); validateTimeout(options.timeout); validateAbortSignal(options.signal, 'options.signal'); const killSignal = sanitizeKillSignal(options.killSignal); @@ -818,6 +820,10 @@ function spawnSync(file, args, options) { debug('spawnSync', options); + // Validate the arguments for null bytes. The normalizeSpawnArguments() + // function already makes sure that the array is present. + validateArgumentsNullCheck(options.args); + // Validate the timeout, if present. validateTimeout(options.timeout); @@ -949,6 +955,15 @@ function execSync(command, options) { } +function validateArgumentsNullCheck(args) { + for (let i = 0; i < args.length; ++i) { + if (StringPrototypeIncludes(args[i], '\u0000')) { + throw new ERR_INVALID_ARG_VALUE('args', args, 'cannot contain null bytes'); + } + } +} + + function validateTimeout(timeout) { if (timeout != null && !(NumberIsInteger(timeout) && timeout >= 0)) { throw new ERR_OUT_OF_RANGE('timeout', 'an unsigned integer', timeout); diff --git a/test/parallel/test-child-process-spawn-reject-null-bytes.js b/test/parallel/test-child-process-spawn-reject-null-bytes.js new file mode 100644 index 00000000000000..242f7424c3c63d --- /dev/null +++ b/test/parallel/test-child-process-spawn-reject-null-bytes.js @@ -0,0 +1,13 @@ +'use strict'; +require('../common'); + +// Regression test for https://github.com/nodejs/node/issues/44768 + +const { throws } = require('assert'); +const { spawn, spawnSync } = require('child_process'); + +throws(() => spawn(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']), + { code: 'ERR_INVALID_ARG_VALUE' }); + +throws(() => spawnSync(process.execPath, [__filename, 'AAA', 'BBB\0XXX', 'CCC']), + { code: 'ERR_INVALID_ARG_VALUE' });