CVE-2021-21388: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection') (CWE-78)
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.
CWE 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.
CVSS v3 base score: 9.8
Published: 2021-04-29T18:15Z
Repository: https://github.com/sebhildebrandt/systeminformation
Language: JavaScript
Files changed: lib/docker.js, lib/internet.js, lib/network.js, lib/processes.js
Commit date: 2021-03-15 11:42:12 +0100
Commit message: sanitizeShellString() and other security improvements

Diff: diff --git a/lib/docker.js b/lib/docker.js
index 235487e2..89705eb6 100644
--- a/lib/docker.js
+++ b/lib/docker.js
@@ -468,11 +468,11 @@ function dockerContainerStats(containerIDs, callback) {
         containerIDsSanitized = containerIDs;
         containerIDsSanitized = containerIDsSanitized.trim();
         if (containerIDsSanitized !== '*') {
           containerIDsSanitized = '';
           const s = (util.isPrototypePolluted() ? '' : util.sanitizeShellString(containerIDs, true)).trim();
-          for (let i = 0; i <= 2000; i++) {
+          for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
             if (!(s[i] === undefined)) {
               s[i].__proto__.toLowerCase = util.stringToLower;
               const sl = s[i].toLowerCase();
               if (sl && sl[0] && !sl[1]) {
                 containerIDsSanitized = containerIDsSanitized + sl[0];
diff --git a/lib/internet.js b/lib/internet.js
index 9ac1e717..1f75a712 100644
--- a/lib/internet.js
+++ b/lib/internet.js
@@ -44,12 +44,11 @@ function inetChecksite(url, callback) {
         if (callback) { callback(result); }
         return resolve(result);
       }
       let urlSanitized = '';
       const s = util.sanitizeShellString(url, true);
-      const mathMin = util.mathMin;
-      for (let i = 0; i <= mathMin(s.length, 2000); i++) {
+      for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
         if (!(s[i] === undefined)) {
           s[i].__proto__.toLowerCase = util.stringToLower;
           const sl = s[i].toLowerCase();
           if (sl && sl[0] && !sl[1] && sl[0].length === 1) {
             urlSanitized = urlSanitized + sl[0];
@@ -143,12 +142,11 @@ function inetLatency(host, callback) {
         if (callback) { callback(null); }
         return resolve(null);
       }
       let hostSanitized = '';
       const s = (util.isPrototypePolluted() ? '8.8.8.8' : util.sanitizeShellString(host, true)).trim();
-      const mathMin = util.mathMin;
-      for (let i = 0; i <= mathMin(s.length, 2000); i++) {
+      for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
         if (!(s[i] === undefined)) {
           s[i].__proto__.toLowerCase = util.stringToLower;
           const sl = s[i].toLowerCase();
           if (sl && sl[0] && !sl[1]) {
             hostSanitized = hostSanitized + sl[0];
diff --git a/lib/network.js b/lib/network.js
index 5398ece2..0dc8d9e1 100644
--- a/lib/network.js
+++ b/lib/network.js
@@ -1059,12 +1059,11 @@ function networkStatsSingle(iface) {
 
   return new Promise((resolve) => {
     process.nextTick(() => {
       let ifaceSanitized = '';
       const s = util.isPrototypePolluted() ? '---' : util.sanitizeShellString(iface);
-      const mathMin = util.mathMin;
-      for (let i = 0; i <= mathMin(s.length, 2000); i++) {
+      for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
         if (!(s[i] === undefined)) {
           ifaceSanitized = ifaceSanitized + s[i];
         }
       }
 
diff --git a/lib/processes.js b/lib/processes.js
index 2f234c6c..510577a6 100644
--- a/lib/processes.js
+++ b/lib/processes.js
@@ -109,12 +109,11 @@ function services(srv, callback) {
         srvString.__proto__.toLowerCase = util.stringToLower;
         srvString.__proto__.replace = util.stringReplace;
         srvString.__proto__.trim = util.stringTrim;
 
         const s = util.sanitizeShellString(srv);
-        const mathMin = util.mathMin;
-        for (let i = 0; i <= mathMin(s.length, 2000); i++) {
+        for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
           if (!(s[i] === undefined)) {
             srvString = srvString + s[i];
           }
         }
 
@@ -909,12 +908,11 @@ function processLoad(proc, callback) {
       processesString.__proto__.toLowerCase = util.stringToLower;
       processesString.__proto__.replace = util.stringReplace;
       processesString.__proto__.trim = util.stringTrim;
 
       const s = util.sanitizeShellString(proc);
-      const mathMin = util.mathMin;
-      for (let i = 0; i <= mathMin(s.length, 2000); i++) {
+      for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
         if (!(s[i] === undefined)) {
           processesString = processesString + s[i];
         }
       }
 

Vulnerable code:           for (let i = 0; i <= 2000; i++) {
      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++) {
      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++) {
      const mathMin = util.mathMin;
      for (let i = 0; i <= mathMin(s.length, 2000); i++) {
Fixed code:           for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
      for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
      for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
      for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
        for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {
      for (let i = 0; i <= util.mathMin(s.length, 2000); i++) {