CVE-2021-21388 (HTML, published 2021-04-29T18:15Z)
Description: value: systeminformation is an open source system and OS information library for node.js. A command injection vulnerability has been discovered in versions of systeminformation prior to 5.6.4. The issue has been fixed with a parameter check on user input. Please upgrade to version >= 5.6.4. If you cannot upgrade, be sure to check or sanitize service parameters that are passed to si.inetLatency(), si.inetChecksite(), si.services(), si.processLoad() and other commands. Only allow strings, reject any arrays. String sanitation works as expected.
Severity: HIGH (CVSS v3 base score: 9.8)
Weakness: CWE-78 \u2014 Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
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/sebhildebrandt/systeminformation
Files changed:
CHANGELOG.md
docs/history.html
docs/index.html
docs/security.html
docs/v4/history.html
docs/v4/index.html
docs/v4/security.html
lib/internet.js
lib/network.js
lib/processes.js
lib/util.js
Commit message: sanitizeShellString() and other security improvements


Vulnerable code:
| 5.6.3          | 2021-03-10     | `sanitizeShellString()` improvement |
      <a href="security.html" class="recommendation">Security advisory:<br>Update to v5.6.3</a>
      <div class="version">New Version: <span id="version">5.6.3</span></div>
                &lt; 5.6.3 and &lt; 4.34.16<br>
                <span class="bold">Date:</span> 2021-03-14<br>
              <p>Problem was fixed with additional parameter checking. Please upgrade to version >= 5.6.3 (or >= 4.34.16 if you are using version 4).</p>
      <a href="security.html" class="recommendation">Security advisory:<br>Update to v4.34.16</a>
      <div class="version">Current Version: <span id="version">4.34.16</span></div>
                &lt; 4.34.13<br>
                <span class="bold">Date:</span> 2021-03-14<br>
              <p>Problem was fixed with additional parameter checking. Please upgrade to version >= 4.34.13 if you are using version 4.</p>
const exec = require('child_process').exec;
      for (let i = 0; i <= 2000; i++) {
          if (sl && sl[0] && !sl[1]) {
            let args = ' -I --connect-timeout 5 -m 5 ' + urlSanitized + ' 2>/dev/null | head -n 1 | cut -d " " -f2';
            exec(cmd + args, function (error, stdout) {
              let statusCode = parseInt(stdout.toString());
              result.ok = !error && (statusCode === 200 || statusCode === 301 || statusCode === 302 || statusCode === 304);
      for (let i = 0; i <= 2000; i++) {
        execFile('ping', params.split(' '), function (error, stdout) {
          if (!error) {
            const lines = stdout.toString().split('\n').filter(line => line.indexOf(filt) >= 0).join('\n');
        execFile('ping', params.split(' '), { timeout: 3000 }, function (error, stdout) {
          if (!error) {
            const lines = stdout.toString().split('\n').filter(line => line.indexOf(filt) >= 0).join('\n');
      for (let i = 0; i <= 2000; i++) {
        for (let i = 0; i <= 2000; i++) {
          if ((_darwin) && srvString === '*') { // service enumeration mnot yet suported on mac OS
          let comm = (_darwin) ? 'ps -caxo pcpu,pmem,pid,command' : 'ps -axo pcpu,pmem,pid,command';
            exec(comm + ' | grep -v grep | grep -iE "' + srvString + '"', { maxBuffer: 1024 * 20000 }, function (error, stdout) {   // lgtm [js/shell-command-constructed-from-input]
              if (!error) {
                let lines = stdout.toString().replace(/ +/g, ' ').replace(/,+/g, '.').split('\n');
                exec('ps -o comm | grep -v grep | egrep "' + srvString + '"', { maxBuffer: 1024 * 20000 }, function (error, stdout) {   // lgtm [js/shell-command-constructed-from-input]
                  if (!error) {
                    let lines = stdout.toString().replace(/ +/g, ' ').replace(/,+/g, '.').split('\n');
      for (let i = 0; i <= 2000; i++) {
  for (let i = 0; i <= 2000; i++) {

Fixed code:
| 5.6.4          | 2021-03-15     | `sanitizeShellString()` and other security improvements |
| 5.6.3          | 2021-03-14     | `sanitizeShellString()` improvement |
                  <tr>
                    <th scope="row">5.6.4</th>
                    <td>2021-03-15</td>
                    <td><span class="code">sanitizeShellString()</span> and other security improvements</td>
                  </tr>
      <a href="security.html" class="recommendation">Security advisory:<br>Update to v5.6.4</a>
      <div class="version">New Version: <span id="version">5.6.4</span></div>
                &lt; 5.6.4 and &lt; 4.34.17<br>
                <span class="bold">Date:</span> 2021-03-15<br>
              <p>Problem was fixed with additional parameter checking. Please upgrade to version >= 5.6.4 (or >= 4.34.17 if you are using version 4).</p>
                  <tr>
                    <th scope="row">4.34.17</th>
                    <td>2021-03-14</td>
                    <td><span class="code">sanitizeShellString()</span> and other security improvements</td>
                  </tr>
      <a href="security.html" class="recommendation">Security advisory:<br>Update to v4.34.17</a>
      <div class="version">Current Version: <span id="version">4.34.17</span></div>
                &lt; 4.34.17<br>
                <span class="bold">Date:</span> 2021-03-15<br>
              <p>Problem was fixed with additional parameter checking. Please upgrade to version >= 4.34.17 if you are using version 4.</p>
// const exec = require('child_process').exec;
      const mathMin = util.mathMin;
      for (let i = 0; i <= mathMin(s.length, 2000); i++) {
          if (sl && sl[0] && !sl[1] && sl[0].length === 1) {
            let args = ['-I', '--connect-timeout', '5', '-m', '5'];
            args.push(urlSanitized);
            util.execSave(cmd, args).then((stdout) => {
              const lines = stdout.split('\n');
              let statusCode = lines[0] && lines[0].indexOf(' ') >= 0 ? parseInt(lines[0].split(' ')[1], 10) : 404;
              result.ok = (statusCode === 200 || statusCode === 301 || statusCode === 302 || statusCode === 304);
      const mathMin = util.mathMin;
      for (let i = 0; i <= mathMin(s.length, 2000); i++) {
        util.execSave('ping', params.split(' ')).then((stdout) => {
          if (stdout) {
            const lines = stdout.split('\n').filter(line => line.indexOf(filt) >= 0).join('\n');
        util.execSave('ping', params.split(' '), { timeout: 3000 }).then((stdout) => {
          if (stdout) {
            const lines = stdout.split('\n').filter(line => line.indexOf(filt) >= 0).join('\n');
      const mathMin = util.mathMin;
      for (let i = 0; i <= mathMin(s.length, 2000); i++) {
        const mathMin = util.mathMin;
        for (let i = 0; i <= mathMin(s.length, 2000); i++) {
          if ((_darwin) && srvString === '*') { // service enumeration not yet suported on mac OS
          let args = (_darwin) ? ['-caxo', 'pcpu,pmem,pid,command'] : ['-axo', 'pcpu,pmem,pid,command'];
            util.execSave('ps', args).then((stdout) => {
              if (stdout) {
                let lines = stdout.replace(/ +/g, ' ').replace(/,+/g, '.').split('\n');
                args = ['-o', 'comm'];
                util.execSave('ps', args).then((stdout) => {
                  if (stdout) {
                    let lines = stdout.replace(/ +/g, ' ').replace(/,+/g, '.').split('\n');
      const mathMin = util.mathMin;
      for (let i = 0; i <= mathMin(s.length, 2000); i++) {
const mathMin = Math.min;
function execSave(cmd, args, options) {
  let result = '';
  options = options || {};

  return new Promise((resolve) => {
    process.nextTick(() => {
      try {
        const child = spawn(cmd, args, options);

        if (child && !child.pid) {
          child.on('error', function () {
            resolve(result);
          });
        }
        if (child && child.pid) {
          child.stdout.on('data', function (data) {
            result += data.toString();
          });
          child.on('close', function () {
            child.kill();
            resolve(result);
          });
          child.on('error', function () {
            child.kill();
            resolve(result);
          });
        } else {
          resolve(result);
        }
      } catch (e) {
        resolve(result);
      }
    });
  });
}

  for (let i = 0; i <= mathMin(s.length, 2000); i++) {
exports.execSave = execSave;
exports.mathMin = mathMin;