CVE-2018-3772 (JavaScript)

Concatenating unsanitized user input in the `whereis` npm module < 0.4.1 allowed an attacker to execute arbitrary commands. The `whereis` module is deprecated and it is recommended to use the `which` npm module instead.

Weakness:
CWE-94: name: Improper Control of Generation of Code ('Code Injection')
description: The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
CWE-77: name: Improper Neutralization of Special Elements used in a Command ('Command Injection')
description: The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.
CWE-78: name: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
description: The product constructs all or part of an OS command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended OS command when it is sent to a downstream component.

Repository: https://github.com/vvo/node-whereis

Vulnerable code:
file_path: index.js
snippet: module.exports = function whereis(name, cb) {
  cp.exec('which ' + name, function(error, stdout, stderr) {
    stdout = stdout.split('\n')[0];
    if (error || stderr || stdout === '' || stdout.charAt(0) !== '/') {
      stdout = stdout.split('\n')[0];
      cp.exec('whereis ' + name, function(error, stdout, stderr) {
        if (error || stderr || stdout === '' || stdout.indexOf( '/' ) === -1) {
          cp.exec('where ' + name, function (error, stdout, stderr) { //windows
            if (error || stderr || stdout === '' || stdout.indexOf('\\') === -1) {
              cp.exec('for %i in (' + name + '.exe) do @echo. %~$PATH:i', function (error, stdout, stderr) { //windows xp
                if (error || stderr || stdout === '' || stdout.indexOf('\\') === -1) {
                  return cb(new Error('Could not find ' + name + ' on your system'));
                }
                return cb(null, stdout);
              });
            } else {
              return cb(null, stdout);
            }
          });
        }
        else {
          return cb(null, stdout.split(' ')[1]);
        }
      });
    } else {
      return cb(null, stdout);
    }
  });
};

Fixed code:
file_path: index.js
snippet: module.exports = function whereis(name, cb) {
  cp.execFile('which', [name], function(error, stdout, stderr) {
    stdout = stdout.split('\n')[0];
    if (error || stderr || stdout === '' || stdout.charAt(0) !== '/') {
      stdout = stdout.split('\n')[0];
      cp.execFile('whereis', [name], function(error, stdout, stderr) {
        if (error || stderr || stdout === '' || stdout.indexOf( '/' ) === -1) {
          cp.execFile('where', [name], function (error, stdout, stderr) { //windows
            if (error || stderr || stdout === '' || stdout.indexOf('\\') === -1) {
              cp.exec('for %i in (' + name + '.exe) do @echo. %~$PATH:i', function (error, stdout, stderr) { //windows xp
                if (error || stderr || stdout === '' || stdout.indexOf('\\') === -1) {
                  return cb(new Error('Could not find ' + name + ' on your system'));
                }
                return cb(null, stdout);
              });
            } else {
              return cb(null, stdout);
            }
          });
        }
        else {
          return cb(null, stdout.split(' ')[1]);
        }
      });
    } else {
      return cb(null, stdout);
    }
  });
};