Skip to content

Commit c6bca3f

Browse files
DanielVenableRafaelGSS
authored andcommitted
child_process: deprecate passing args to spawn and execFile
Accepting `args` gives the false impression that the args are escaped while really they are just concatenated. This makes it easy to introduce bugs and security vulnerabilities. PR-URL: #57199 Fixes: #57143 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent b5eddef commit c6bca3f

File tree

5 files changed

+31
-1
lines changed

5 files changed

+31
-1
lines changed

doc/api/deprecations.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3856,13 +3856,16 @@ deprecated, as their values are guaranteed to be identical to that of `process.f
38563856

38573857
<!-- YAML
38583858
changes:
3859+
- version: REPLACEME
3860+
pr-url: https://github.com/nodejs/node/pull/57199
3861+
description: Runtime deprecation.
38593862
- version:
38603863
- REPLACEME
38613864
pr-url: https://github.com/nodejs/node/pull/57389
38623865
description: Documentation-only deprecation.
38633866
-->
38643867

3865-
Type: Documentation-only
3868+
Type: Runtime
38663869

38673870
When an `args` array is passed to [`child_process.execFile`][] or [`child_process.spawn`][] with the option
38683871
`{ shell: true }`, the values are not escaped, only space-separated, which can lead to shell injection.

lib/child_process.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,7 @@ function copyProcessEnvToEnv(env, name, optionEnv) {
535535
}
536536
}
537537

538+
let emittedDEP0190Already = false;
538539
function normalizeSpawnArguments(file, args, options) {
539540
validateString(file, 'file');
540541
validateArgumentNullCheck(file, 'file');
@@ -611,6 +612,14 @@ function normalizeSpawnArguments(file, args, options) {
611612

612613
if (options.shell) {
613614
validateArgumentNullCheck(options.shell, 'options.shell');
615+
if (args.length > 0 && !emittedDEP0190Already) {
616+
process.emitWarning(
617+
'Passing args to a child process with shell option true can lead to security ' +
618+
'vulnerabilities, as the arguments are not escaped, only concatenated.',
619+
'DeprecationWarning',
620+
'DEP0190');
621+
emittedDEP0190Already = true;
622+
}
614623
const command = ArrayPrototypeJoin([file, ...args], ' ');
615624
// Set the shell, switches, and commands.
616625
if (process.platform === 'win32') {

test/parallel/test-child-process-execfile.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ const fixture = fixtures.path('exit.js');
1212
const echoFixture = fixtures.path('echo.js');
1313
const execOpts = { encoding: 'utf8', shell: true, env: { ...process.env, NODE: process.execPath, FIXTURE: fixture } };
1414

15+
common.expectWarning(
16+
'DeprecationWarning',
17+
'Passing args to a child process with shell option true can lead to security ' +
18+
'vulnerabilities, as the arguments are not escaped, only concatenated.',
19+
'DEP0190');
20+
1521
{
1622
execFile(
1723
process.execPath,

test/parallel/test-child-process-spawn-shell.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ doesNotExist.on('exit', common.mustCall((code, signal) => {
1818
}));
1919

2020
// Verify that passing arguments works
21+
common.expectWarning(
22+
'DeprecationWarning',
23+
'Passing args to a child process with shell option true can lead to security ' +
24+
'vulnerabilities, as the arguments are not escaped, only concatenated.',
25+
'DEP0190');
26+
2127
const echo = cp.spawn('echo', ['foo'], {
2228
encoding: 'utf8',
2329
shell: true

test/parallel/test-child-process-spawnsync-shell.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ else
1919
assert.strictEqual(doesNotExist.status, 127); // Exit code of /bin/sh
2020

2121
// Verify that passing arguments works
22+
common.expectWarning(
23+
'DeprecationWarning',
24+
'Passing args to a child process with shell option true can lead to security ' +
25+
'vulnerabilities, as the arguments are not escaped, only concatenated.',
26+
'DEP0190');
27+
2228
internalCp.spawnSync = common.mustCall(function(opts) {
2329
assert.strictEqual(opts.args[opts.args.length - 1].replace(/"/g, ''),
2430
'echo foo');

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy