mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
47b877993f
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: https://github.com/nodejs/node/pull/53781 Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
92 lines
2.8 KiB
JavaScript
92 lines
2.8 KiB
JavaScript
import * as common from '../common/index.mjs';
|
|
import * as fixtures from '../common/fixtures.mjs';
|
|
import { EOL } from 'node:os';
|
|
import { strictEqual, notStrictEqual, throws } from 'node:assert';
|
|
import cp from 'node:child_process';
|
|
|
|
// TODO(LiviaMedeiros): test on different platforms
|
|
if (!common.isLinux)
|
|
common.skip();
|
|
|
|
const expectedCWD = process.cwd();
|
|
const expectedUID = process.getuid();
|
|
|
|
for (const tamperedCwd of ['', '/tmp', '/not/existing/malicious/path', 42n]) {
|
|
Object.prototype.cwd = tamperedCwd;
|
|
|
|
cp.exec('pwd', common.mustSucceed((out) => {
|
|
strictEqual(`${out}`, `${expectedCWD}${EOL}`);
|
|
}));
|
|
strictEqual(`${cp.execSync('pwd')}`, `${expectedCWD}${EOL}`);
|
|
cp.execFile('pwd', common.mustSucceed((out) => {
|
|
strictEqual(`${out}`, `${expectedCWD}${EOL}`);
|
|
}));
|
|
strictEqual(`${cp.execFileSync('pwd')}`, `${expectedCWD}${EOL}`);
|
|
cp.spawn('pwd').stdout.on('data', common.mustCall((out) => {
|
|
strictEqual(`${out}`, `${expectedCWD}${EOL}`);
|
|
}));
|
|
strictEqual(`${cp.spawnSync('pwd').stdout}`, `${expectedCWD}${EOL}`);
|
|
|
|
delete Object.prototype.cwd;
|
|
}
|
|
|
|
for (const tamperedUID of [0, 1, 999, 1000, 0n, 'gwak']) {
|
|
Object.prototype.uid = tamperedUID;
|
|
|
|
cp.exec('id -u', common.mustSucceed((out) => {
|
|
strictEqual(`${out}`, `${expectedUID}${EOL}`);
|
|
}));
|
|
strictEqual(`${cp.execSync('id -u')}`, `${expectedUID}${EOL}`);
|
|
cp.execFile('id', ['-u'], common.mustSucceed((out) => {
|
|
strictEqual(`${out}`, `${expectedUID}${EOL}`);
|
|
}));
|
|
strictEqual(`${cp.execFileSync('id', ['-u'])}`, `${expectedUID}${EOL}`);
|
|
cp.spawn('id', ['-u']).stdout.on('data', common.mustCall((out) => {
|
|
strictEqual(`${out}`, `${expectedUID}${EOL}`);
|
|
}));
|
|
strictEqual(`${cp.spawnSync('id', ['-u']).stdout}`, `${expectedUID}${EOL}`);
|
|
|
|
delete Object.prototype.uid;
|
|
}
|
|
|
|
{
|
|
Object.prototype.execPath = '/not/existing/malicious/path';
|
|
|
|
// Does not throw ENOENT
|
|
cp.fork(fixtures.path('empty.js'));
|
|
|
|
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;
|
|
}
|