Skip to content

Command injection in generated npm launcher (jdeploy.js) via unescaped arguments passed to exec() #464

Description

@andrii-bodnar

The npm launcher jDeploy generates (jdeploy-bundle/jdeploy.js) wraps each CLI argument in double quotes without escaping and runs the result with exec(). An argument with an embedded " plus shell metacharacters breaks out and executes arbitrary commands. This affects every package published with jDeploy.

Affected code

The launcher script jDeploy bundles into each package as jdeploy-bundle/jdeploy.js (the jdeploy.js template shipped inside JDeploy.jar). Still present in jdeploy@6.1.5:

programArgs.forEach(function(arg) {
    cmd += ' "'+arg+'"';   // embedded " not escaped
});
var child = exec(cmd, {async: true});

Proof of concept

./node_modules/.bin/<app> 'x";touch${IFS}/tmp/jdeploy-pwn;#'
test -f /tmp/jdeploy-pwn && echo "VULNERABLE"

The injected command runs before the app's own argument validation rejects it. A payload like this is even a valid Git branch name, so it can reach the launcher through normal CI automation (branch names, PR metadata, paths).

  • Type: OS command injection (CWE-78)
  • CVSS v3.1: AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H (~7.3 High)

Suggested fix

Use an argv-based API with shell: false instead of building a shell string:

const { spawn } = require('child_process');
const child = spawn(javaBinary,
    [...javaArgs, '-jar', path.join(__dirname, jarName), ...programArgs],
    { stdio: 'inherit', shell: false, env });
child.on('close', code => process.exit(code));

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions