diff --git a/src/node_task_runner.cc b/src/node_task_runner.cc index 9263a502a45f..e7cc9ccf3f13 100644 --- a/src/node_task_runner.cc +++ b/src/node_task_runner.cc @@ -154,7 +154,7 @@ std::string EscapeShell(const std::string_view input) { } static constexpr std::string_view forbidden_characters = - "[\t\n\r \"#$&'()*;<>?\\\\`|~]"; + "[\t\n\r \"#$&'()*;<>%?\\\\`|~]"; // Check if input contains any forbidden characters // If it doesn't, return the input as is. @@ -174,6 +174,7 @@ std::string EscapeShell(const std::string_view input) { static const std::regex tripleSingleQuote("\\\\\"\"\""); escaped = std::regex_replace(escaped, leadingQuotePairs, ""); escaped = std::regex_replace(escaped, tripleSingleQuote, "\\\""); + escaped = std::regex_replace(escaped, std::regex("%"), "^%"); #else // Replace single quotes("'") with `'"'"'` and wrap the result // in single quotes. diff --git a/test/parallel/test-node-run.js b/test/parallel/test-node-run.js index ece9e48878b3..bac90cf5db58 100644 --- a/test/parallel/test-node-run.js +++ b/test/parallel/test-node-run.js @@ -12,7 +12,7 @@ const fixtures = require('../common/fixtures'); const tmpdir = require('../common/tmpdir'); const envSuffix = common.isWindows ? '-windows' : ''; -describe('node --run [command]', () => { +describe('node --run [command]', { concurrency: !process.env.TEST_PARALLEL }, () => { it('returns error on non-existent file', async () => { const child = await common.spawnPromisified( process.execPath, @@ -286,4 +286,19 @@ describe('node --run [command]', () => { assert.strictEqual(child.stdout, ''); assert.strictEqual(child.code, 1); }); + + it('escapes shell characters', async () => { + const child = await common.spawnPromisified( + process.execPath, + [ '--run', `positional-args${envSuffix}`, '--', '%PAYLOAD%', '$PAYLOAD'], + { cwd: fixtures.path('run-script'), env: { ...process.env, PAYLOAD: 'env value' } }, + ); + assert.strictEqual( + child.stdout, + common.isWindows ? + `Raw '"^%PAYLOAD^%" "$PAYLOAD"'\r\nArguments: '%PAYLOAD% $PAYLOAD'\r\nThe total number of arguments is: 2\r\n` : + "Arguments: '%PAYLOAD% $PAYLOAD'\nThe total number of arguments is: 2\n"); + assert.strictEqual(child.stderr, ''); + assert.strictEqual(child.code, 0); + }); });