Skip to content

Commit

Permalink
child_process: fix incomplete prototype pollution hardening
Browse files Browse the repository at this point in the history
Prior pull request (#48726) hardened against prototype pollution
vulnerabilities but effectively missed some use-cases which
opened a window for prototype pollution for some child_process
functions such as spawn(), spawnSync(), and execFileSync().

PR-URL: #53781
Reviewed-By: Vinícius Lourenço Claro Cardoso <[email protected]>
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Rafael Gonzaga <[email protected]>
  • Loading branch information
lirantal authored Jul 21, 2024
1 parent 1fb23f1 commit 47b8779
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 1 deletion.
1 change: 1 addition & 0 deletions lib/child_process.js
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,7 @@ function normalizeSpawnArguments(file, args, options) {
else
validateObject(options, 'options');

options = { __proto__: null, ...options };
let cwd = options.cwd;

// Validate the cwd, if present.
Expand Down
34 changes: 33 additions & 1 deletion test/parallel/test-child-process-prototype-tampering.mjs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as common from '../common/index.mjs';
import * as fixtures from '../common/fixtures.mjs';
import { EOL } from 'node:os';
import { strictEqual } from 'node:assert';
import { strictEqual, notStrictEqual, throws } from 'node:assert';
import cp from 'node:child_process';

// TODO(LiviaMedeiros): test on different platforms
Expand Down Expand Up @@ -57,3 +57,35 @@ for (const tamperedUID of [0, 1, 999, 1000, 0n, 'gwak']) {

delete Object.prototype.execPath;
}

for (const shellCommandArgument of ['-L && echo "tampered"']) {
Object.prototype.shell = true;
const cmd = 'pwd';
let cmdExitCode = '';

const program = cp.spawn(cmd, [shellCommandArgument], { cwd: expectedCWD });
program.stderr.on('data', common.mustCall());
program.stdout.on('data', common.mustNotCall());

program.on('exit', common.mustCall((code) => {
notStrictEqual(code, 0);
}));

cp.execFile(cmd, [shellCommandArgument], { cwd: expectedCWD },
common.mustCall((err) => {
notStrictEqual(err.code, 0);
})
);

throws(() => {
cp.execFileSync(cmd, [shellCommandArgument], { cwd: expectedCWD });
}, (e) => {
notStrictEqual(e.status, 0);
return true;
});

cmdExitCode = cp.spawnSync(cmd, [shellCommandArgument], { cwd: expectedCWD }).status;
notStrictEqual(cmdExitCode, 0);

delete Object.prototype.shell;
}

0 comments on commit 47b8779

Please sign in to comment.