Link Search Menu Expand Document

OS Command Injection in NodeJS

Vulnerable example

Node.js provides several ways to execute external programs as part of the child_process package. The exec method spawns a shell then executes the command within that shell. It is important to never pass unsanitized user input to this function. Similarly, the two other variants execFile and spawn have a shell option (which defaults to false). If enabled, the method executes the provided command inside a system shell; in these cases, it is important to never pass unsanitized user input to the function.

The following example uses the execSync (synchronous version of exec) to run a system command with unsanitized user input:

const output = child_process.execSync(`ping -c 1 '${destination}'`);

Note that wrapping destination in single quotes is not a sufficient countermeasure.

Prevention

Since Node.js lacks a proper shell-escaping mechanism, when possible, refrain from using a proper shell invocation and leverage Node.js APIs. If this is not possible, execution of external commands should be handled by using other methods (execFile and spawn) to directly invoke the desired command, instead of by invoking a system shell. By passing individual program arguments to this method, the argument injection is avoided. For example:

const output = child_process.spawnSync('ping', ['-c', '1', destination]);

The value of destination is always passed as a single argument to ping.

References

https://cwe.mitre.org/data/definitions/78.html https://www.owasp.org/index.php/Command_Injection