Vulnerability: Command Execution in windows-cpu Version of `windows-cpu` before 0.1.5 will execute arbitrary code passed into the first argument of the `findLoad` method, resulting in remote code execution.

## Proof of Concept

```
var win = require('windows-cpu');
wind.findLoad('foo & calc.exe');
```


## Recommendation

Update to version 0.1.5 or later.
Vulnerability ID: GHSA-63m4-fhf2-cmf7
CWE: CWE-78
Severity score: 9.8
Project: https://github.com/KyleRoss/windows-cpu
Published: 2020-09-01
File: index.js
Commit message: ES6 Refactor + fix vulnerability
Commit author: Kyle Ross

Vulnerable version (before fix):
 /**  * windows-cpu module for Node.js to get various load statistics.  * @module windows-cpu  * @version 0.1.4  * @author Kyle Ross <kylerross1324@gmail.com>  * @license MIT License  *   * @requires os  * @requires child_process  *  * @example  *  * var cpu = require('windows-cpu');  */  (function() {     var platform = require('os').platform(),         path     = require('path'),         exec     = require('child_process').exec,         execFile = require('child_process').execFile,         wmic     = platform === 'win32'? path.join(process.env.SystemRoot, 'System32', 'wbem', 'wmic.exe') : null,         emptyFn  = function(){},         findLoad;          /*      * Checks current platform to ensure we are running on `win32`.      * @private      * @param {function} cb A callback function to call if there is an error.      * @returns {boolean} True if `win32` platform, else false.      */     function checkPlatform(cb) {         if(platform !== 'win32') {             if(isFunction(cb)) cb(new Error('windows-cpu> [ERROR] This module only works on Windows platforms.'));             return false;         }         return true;     }          /*      * Proper checking to see if variable is a function.      * @private      * @param {*} fn The variable to check if is a function.      * @returns {boolean} True if is a function, else false.      */     function isFunction(fn) {         var getType = {};         return fn && getType.toString.call(fn) === '[object Function]';     }          /**      * Gets the total load in percent for process(es) by a specific search parameter.      * @param {string|number} arg Specific search parameter. Can be a Process ID or Process Name.      * @param {function} cb A callback function to handle the results (error, results).      * @example      *      * var cpu = require('windows-cpu');      *      * // Find the total load for "chrome" processes      * cpu.findLoad('chrome', function(error, results) {      *      if(error) {      *          return console.log(error);      *      }      *      *      // results =>      *      // {      *      //    load: 8,      *      //    found: [      *      //        { pid: '900', process: 'chrome', load: 4 },      *      //        { pid: '905', process: 'chrome#1', load: 0 },      *      //        { pid: '910', process: 'chrome#2', load: 4 }      *      //    ]      *      // }      *      *      console.log('Google Chrome is currently using ' + results.load + '% of the cpu.');      * });      */     findLoad = exports.findLoad = function findLoad(arg, cb) {         if(!isFunction(cb)) cb = emptyFn;         if(!checkPlatform(cb)) return;                  var cmd = "wmic path Win32_PerfFormattedData_PerfProc_Process get Name,PercentProcessorTime,IDProcess | findstr /i /c:" + arg;         exec(cmd, function (error, res, stderr) {             if(error !== null || stderr) return cb(error || stderr);             if(!res) return cb('Cannot find results for provided arg: ' + arg, { load: 0, results: [] });                          var found = res.replace(/[^\S\n]+/g, ':').replace(/\:\s/g, '|').split('|').filter(function(v) {                 return !!v;             }).map(function(v) {                 var data = v.split(':');                 return {                     pid: +data[0],                     process: data[1],                     load: +data[2]                 };             });                          var totalLoad = 0;                          found.forEach(function(obj) {                 totalLoad += obj.load;             });                          var output = {                 load: totalLoad,                 found: found             };                          cb(null, output);         });     };          /**      * Gets the total load in percent for all processes running on the current machine per CPU.      * @param {function} cb A callback function to handle the results (error, results).      * @example      *      * var cpu = require('windows-cpu');      *      * // Get total load on server for each CPU      * cpu.totalLoad(function(error, results) {      *      // [3, 10]      * });      */     exports.totalLoad = function totalLoad(cb) {         if (!isFunction(cb)) cb = emptyFn;         if (!checkPlatform(cb)) return;                  execFile(wmic, ['cpu', 'get', 'loadpercentage'], function (error, res, stderr) {             if(error !== null || stderr) return cb(error || stderr);                          var cpus = (res.match(/\d+/g) || []).map(function(x) {                  return +(x.trim());              });                          cb(null, cpus);         });     };          /**      * Gets the total load in percent for all Node.js processes running on the current machine.      * @param {function} cb A callback function to handle the results (error, results).      * @example      *      * var cpu = require('windows-cpu');      *      * // Get total load for all node processes      * cpu.nodeLoad(function(error, results) {      *      //    ]      *      // }      *      *      console.log('Total Node.js Load: ' + results.load);      * });      */     exports.nodeLoad = function nodeLoad(cb) {         findLoad('node', cb);     };          /**      * Gets the total load in percent for all processes running on the current machine per CPU.      * @param {function} cb A callback function to handle the results (error, results).      * @example      *      * var cpu = require('windows-cpu');      *      * // Get load for current running node process      * cpu.processLoad(function(error, results) {      *      //    ]      *      // }      *      *      console.log('Total Process Load: ' + results.load);      * });      */     exports.processLoad = function processLoad(cb) {         findLoad(process.pid, cb);     };          /**      * Gets the name of each processor in the machine.      * @param {function} cb A callback function to handle the results (error, results).      * @example      *      * var cpu = require('windows-cpu');      *      * // Get listing of processors      * cpu.cpuInfo(function(error, results) {      *      console.log('Installed Processors: ', results);      * });      */     exports.cpuInfo = function cpuInfo(cb) {         if(!isFunction(cb)) cb = emptyFn;         if(!checkPlatform(cb)) return;                  execFile(wmic, ['cpu', 'get', 'Name'], function (error, res, stderr) {             if(error !== null || stderr) return cb(error || stderr);                          var cpus = res.match(/[^\r\n]+/g).map(function(v) {                 return v.trim();             });                          cpus.shift();             cb(null, cpus);         });     };      /**      * Gets the total memory usage value in KB , MB and GB .      * @param {function} cb A callback function to handle the result (error, results).      * @example      *      * var cpu = require('windows-cpu');      *      * // Get the memory usage      * cpu.totalMemoryUsage(function(error, results) {      *      console.log('Total Memory Usage: ', result);      * });      */     exports.totalMemoryUsage = function totalMemoryUsage(cb) {         if (!isFunction(cb)) cb = emptyFn;         if (!checkPlatform(cb)) return;                  var cmd = "tasklist /FO csv /nh";         exec(cmd, function (error, res, stderr) {             if(error !== null || stderr) return cb(error || stderr);             var results = { usageInKb: 0 , usageInMb: 0 , usageInGb: 0 };                          results.usageInKb = res.match(/[^\r\n]+/g).map(function(v) {                 var amt = +v.split('","')[4].replace(/[^\d]/g, '');                 return (!isNaN(amt) && typeof amt === 'number')? amt : 0;             }).reduce(function(prev, current) {                 return prev + current;                          cb(null, results);         });     }; }());

Fixed version (after fix):
 /**  * windows-cpu module for Node.js to get various load statistics.  * @module windows-cpu  * @version 1.0.0  * @author Kyle Ross  * @license MIT License  */ "use strict";  const fs = require('fs'); const path = require('path'); const cp = require('child_process'); const platform = require('os').platform();  const exec = cp.exec; const execFile = cp.execFile; const wmic = path.join(process.env.SystemRoot, 'System32', 'wbem', 'wmic.exe');  /**  * Finds the current processor load of a specific process name or id.  * @private  * @param  {String}   arg Process name or id to lookup  * @param  {Function} cb  Callback to call with results  */ function findLoad(arg, cb) {     let cmd = `wmic path Win32_PerfFormattedData_PerfProc_Process get Name,PercentProcessorTime,IDProcess | findstr /i /c:${arg}`;          exec(cmd, function(error, res, stderr) {         if(error !== null || stderr) return cb(error || stderr);         if(!res) return cb(`Cannot find results for provided arg: ${arg}`, { load: 0, results: [] });                  let found = res.replace(/[^\S\n]+/g, ':').replace(/:\s/g, '|').split('|').filter(function(v) {             return !!v;         }).map(function(v) {             let [pid, proc, load] = v.split(':');             return {                 pid: +pid,                 process: proc,                 load: +load             };         });                  let load = found.reduce((acc, val) => {             return acc + val.load;         }, 0);                  cb(null, { load, found });     }); }  /**  * @class Public class for WindowsCPU  */ class WindowsCPU {     constructor() {         /**          * Access to uninstantiated WindowsCPU class          * @type {Class}          */         this.WindowsCPU = WindowsCPU;         this.checkPlatform();     }          /**      * Checks if the current platform is supported by windows-cpu      * @return {Boolean} Returns `true` if platform is supported      * @throws {Error} If platform is not Windows      * @throws {Error} If wmic.exe process does not exist or cannot be accessed      */     checkPlatform() {         if(platform !== 'win32')              throw new Error('windows-cpu only works on Windows platforms.');                  try {             fs.accessSync(wmic);         } catch(e) {             throw new Error('windows-cpu is not supported on your version of Windows or you are not running as administrator.');         }                  return true;     }          /**      * Gets the total load in percent for all processes running on the current machine per CPU.      * @param  {Function} cb Callback to call with results (error, results)      * @return {WindowsCPU}  Instance of the WindowsCPU class      * @example      *      * const cpu = require('windows-cpu');      *      * // Get total load on server for each CPU      * cpu.totalLoad(function(error, results) {      *      // [3, 10]      * });      */     totalLoad(cb) {         execFile(wmic, ['cpu', 'get', 'loadpercentage'], function(error, res, stderr) {             if(error !== null || stderr) return cb(error || stderr);                          let cpus = (res.match(/\d+/g) || []).map(function(x) {                  return +(x.trim());              });                          cb(null, cpus);         });                  return this;     }          /**      * Retrieves the current cpu load for all node processes running on the current machine      * @param  {Function} cb Callback to call with results (error, results)      * @return {WindowsCPU}  Instance of the WindowsCPU class      * @example      *      * const cpu = require('windows-cpu');      *      * // Get total load for all node processes      * cpu.nodeLoad(function(error, results) {      *      //    ]      *      // }      *      *      console.log(`Total Node.js Load: ${results.load}%`);      * });      */     nodeLoad(cb) {         findLoad('node', cb);         return this;     }          /**      * Retrieves the current cpu load for this process.      * @param  {Function} cb Callback to call with results (error, results)      * @return {WindowsCPU}  Instance of the WindowsCPU class      * @example      *      * const cpu = require('windows-cpu');      *      * // Get load for current running node process      * cpu.processLoad(function(error, results) {      *      //    ]      *      // }      *      *      console.log(`Total Process Load: ${results.load}%`);      * });      */     processLoad(cb) {         findLoad(process.pid, cb);         return this;     }          /**      * Gets list of all processors in the current machine.      * @param  {Function} cb Callback to call with results (error, results)      * @return {WindowsCPU}  Instance of the WindowsCPU class      * @example      *      * const cpu = require('windows-cpu');      *      * // Get listing of processors      * cpu.cpuInfo(function(error, results) {      *      console.log('Installed Processors: ', results);      * });      */     cpuInfo(cb) {         execFile(wmic, ['cpu', 'get', 'Name'], function(error, res, stderr) {             if(error !== null || stderr) return cb(error || stderr);                          let cpus = res.match(/[^\r\n]+/g).map(function(v) {                 return v.trim();             });                          cpus.shift();             cb(null, cpus);         });                  return this;     }          /**      * Gets the total memory usage on the machine in KB, MB and GB.      * @param  {Function} cb Callback to call with results (error, results)      * @return {WindowsCPU}  Instance of the WindowsCPU class      * @example      *      * const cpu = require('windows-cpu');      *      * // Get the memory usage      * cpu.totalMemoryUsage(function(error, results) {      *      console.log('Total Memory Usage: ', result);      * });      */     totalMemoryUsage(cb) {         let cmd = 'tasklist /FO csv /nh';         exec(cmd, function(error, res, stderr) {             if(error !== null || stderr) return cb(error || stderr);             let results = { usageInKb: 0 , usageInMb: 0 , usageInGb: 0 };                          results.usageInKb = res.match(/[^\r\n]+/g).map(function(v) {                 let amt = +v.split('","')[4].replace(/[^\d]/g, '');                 return (!isNaN(amt) && typeof amt === 'number')? amt : 0;             }).reduce(function(prev, current) {                 return prev + current;                          cb(null, results);         });                  return this;     } }  module.exports = new WindowsCPU();

Patch:
patch: @@ -1,120 +1,92 @@
 /**
  * windows-cpu module for Node.js to get various load statistics.
  * @module windows-cpu
- * @version 0.1.4
- * @author Kyle Ross <kylerross1324@gmail.com>
+ * @version 1.0.0
+ * @author Kyle Ross
  * @license MIT License
- * 
- * @requires os
- * @requires child_process
- *
- * @example
- *
- * var cpu = require('windows-cpu');
  */
+"use strict";
 
-(function() {
-    var platform = require('os').platform(),
-        path     = require('path'),
-        exec     = require('child_process').exec,
-        execFile = require('child_process').execFile,
-        wmic     = platform === 'win32'? path.join(process.env.SystemRoot, 'System32', 'wbem', 'wmic.exe') : null,
-        emptyFn  = function(){},
-        findLoad;
-    
-    /*
-     * Checks current platform to ensure we are running on `win32`.
-     * @private
-     * @param {function} cb A callback function to call if there is an error.
-     * @returns {boolean} True if `win32` platform, else false.
-     */
-    function checkPlatform(cb) {
-        if(platform !== 'win32') {
-            if(isFunction(cb)) cb(new Error('windows-cpu> [ERROR] This module only works on Windows platforms.'));
-            return false;
-        }
-        return true;
-    }
+const fs = require('fs');
+const path = require('path');
+const cp = require('child_process');
+const platform = require('os').platform();
+
+const exec = cp.exec;
+const execFile = cp.execFile;
+const wmic = path.join(process.env.SystemRoot, 'System32', 'wbem', 'wmic.exe');
+
+/**
+ * Finds the current processor load of a specific process name or id.
+ * @private
+ * @param  {String}   arg Process name or id to lookup
+ * @param  {Function} cb  Callback to call with results
+ */
+function findLoad(arg, cb) {
+    let cmd = `wmic path Win32_PerfFormattedData_PerfProc_Process get Name,PercentProcessorTime,IDProcess | findstr /i /c:${arg}`;
     
-    /*
-     * Proper checking to see if variable is a function.
-     * @private
-     * @param {*} fn The variable to check if is a function.
-     * @returns {boolean} True if is a function, else false.
-     */
-    function isFunction(fn) {
-        var getType = {};
-        return fn && getType.toString.call(fn) === '[object Function]';
+    exec(cmd, function(error, res, stderr) {
+        if(error !== null || stderr) return cb(error || stderr);
+        if(!res) return cb(`Cannot find results for provided arg: ${arg}`, { load: 0, results: [] });
+        
+        let found = res.replace(/[^\S\n]+/g, ':').replace(/:\s/g, '|').split('|').filter(function(v) {
+            return !!v;
+        }).map(function(v) {
+            let [pid, proc, load] = v.split(':');
+            return {
+                pid: +pid,
+                process: proc,
+                load: +load
+            };
+        });
+        
+        let load = found.reduce((acc, val) => {
+            return acc + val.load;
+        }, 0);
+        
+        cb(null, { load, found });
+    });
+}
+
+/**
+ * @class Public class for WindowsCPU
+ */
+class WindowsCPU {
+    constructor() {
+        /**
+         * Access to uninstantiated WindowsCPU class
+         * @type {Class}
+         */
+        this.WindowsCPU = WindowsCPU;
+        this.checkPlatform();
     }
     
     /**
-     * Gets the total load in percent for process(es) by a specific search parameter.
-     * @param {string|number} arg Specific search parameter. Can be a Process ID or Process Name.
-     * @param {function} cb A callback function to handle the results (error, results).
-     * @example
-     *
-     * var cpu = require('windows-cpu');
-     *
-     * // Find the total load for "chrome" processes
-     * cpu.findLoad('chrome', function(error, results) {
-     *      if(error) {
-     *          return console.log(error);
-     *      }
-     *
-     *      // results =>
-     *      // {
-     *      //    load: 8,
-     *      //    found: [
-     *      //        { pid: '900', process: 'chrome', load: 4 },
-     *      //        { pid: '905', process: 'chrome#1', load: 0 },
-     *      //        { pid: '910', process: 'chrome#2', load: 4 }
-     *      //    ]
-     *      // }
-     *
-     *      console.log('Google Chrome is currently using ' + results.load + '% of the cpu.');
-     * });
+     * Checks if the current platform is supported by windows-cpu
+     * @return {Boolean} Returns `true` if platform is supported
+     * @throws {Error} If platform is not Windows
+     * @throws {Error} If wmic.exe process does not exist or cannot be accessed
      */
-    findLoad = exports.findLoad = function findLoad(arg, cb) {
-        if(!isFunction(cb)) cb = emptyFn;
-        if(!checkPlatform(cb)) return;
+    checkPlatform() {
+        if(platform !== 'win32') 
+            throw new Error('windows-cpu only works on Windows platforms.');
         
-        var cmd = "wmic path Win32_PerfFormattedData_PerfProc_Process get Name,PercentProcessorTime,IDProcess | findstr /i /c:" + arg;
-        exec(cmd, function (error, res, stderr) {
-            if(error !== null || stderr) return cb(error || stderr);
-            if(!res) return cb('Cannot find results for provided arg: ' + arg, { load: 0, results: [] });
-            
-            var found = res.replace(/[^\S\n]+/g, ':').replace(/\:\s/g, '|').split('|').filter(function(v) {
-                return !!v;
-            }).map(function(v) {
-                var data = v.split(':');
-                return {
-                    pid: +data[0],
-                    process: data[1],
-                    load: +data[2]
-                };
-            });
-            
-            var totalLoad = 0;
-            
-            found.forEach(function(obj) {
-                totalLoad += obj.load;
-            });
-            
-            var output = {
-                load: totalLoad,
-                found: found
-            };
-            
-            cb(null, output);
-        });
-    };
+        try {
+            fs.accessSync(wmic);
+        } catch(e) {
+            throw new Error('windows-cpu is not supported on your version of Windows or you are not running as administrator.');
+        }
+        
+        return true;
+    }
     
     /**
      * Gets the total load in percent for all processes running on the current machine per CPU.
-     * @param {function} cb A callback function to handle the results (error, results).
+     * @param  {Function} cb Callback to call with results (error, results)
+     * @return {WindowsCPU}  Instance of the WindowsCPU class
      * @example
      *
-     * var cpu = require('windows-cpu');
+     * const cpu = require('windows-cpu');
      *
      * // Get total load on server for each CPU
      * cpu.totalLoad(function(error, results) {
@@ -129,27 +101,27 @@
      *      // [3, 10]
      * });
      */
-    exports.totalLoad = function totalLoad(cb) {
-        if (!isFunction(cb)) cb = emptyFn;
-        if (!checkPlatform(cb)) return;
-        
-        execFile(wmic, ['cpu', 'get', 'loadpercentage'], function (error, res, stderr) {
+    totalLoad(cb) {
+        execFile(wmic, ['cpu', 'get', 'loadpercentage'], function(error, res, stderr) {
             if(error !== null || stderr) return cb(error || stderr);
             
-            var cpus = (res.match(/\d+/g) || []).map(function(x) { 
+            let cpus = (res.match(/\d+/g) || []).map(function(x) { 
                 return +(x.trim()); 
             });
             
             cb(null, cpus);
         });
-    };
+        
+        return this;
+    }
     
     /**
-     * Gets the total load in percent for all Node.js processes running on the current machine.
-     * @param {function} cb A callback function to handle the results (error, results).
+     * Retrieves the current cpu load for all node processes running on the current machine
+     * @param  {Function} cb Callback to call with results (error, results)
+     * @return {WindowsCPU}  Instance of the WindowsCPU class
      * @example
      *
-     * var cpu = require('windows-cpu');
+     * const cpu = require('windows-cpu');
      *
      * // Get total load for all node processes
      * cpu.nodeLoad(function(error, results) {
@@ -167,19 +139,21 @@
      *      //    ]
      *      // }
      *
-     *      console.log('Total Node.js Load: ' + results.load);
+     *      console.log(`Total Node.js Load: ${results.load}%`);
      * });
      */
-    exports.nodeLoad = function nodeLoad(cb) {
+    nodeLoad(cb) {
         findLoad('node', cb);
-    };
+        return this;
+    }
     
     /**
-     * Gets the total load in percent for all processes running on the current machine per CPU.
-     * @param {function} cb A callback function to handle the results (error, results).
+     * Retrieves the current cpu load for this process.
+     * @param  {Function} cb Callback to call with results (error, results)
+     * @return {WindowsCPU}  Instance of the WindowsCPU class
      * @example
      *
-     * var cpu = require('windows-cpu');
+     * const cpu = require('windows-cpu');
      *
      * // Get load for current running node process
      * cpu.processLoad(function(error, results) {
@@ -195,19 +169,21 @@
      *      //    ]
      *      // }
      *
-     *      console.log('Total Process Load: ' + results.load);
+     *      console.log(`Total Process Load: ${results.load}%`);
      * });
      */
-    exports.processLoad = function processLoad(cb) {
+    processLoad(cb) {
         findLoad(process.pid, cb);
-    };
+        return this;
+    }
     
     /**
-     * Gets the name of each processor in the machine.
-     * @param {function} cb A callback function to handle the results (error, results).
+     * Gets list of all processors in the current machine.
+     * @param  {Function} cb Callback to call with results (error, results)
+     * @return {WindowsCPU}  Instance of the WindowsCPU class
      * @example
      *
-     * var cpu = require('windows-cpu');
+     * const cpu = require('windows-cpu');
      *
      * // Get listing of processors
      * cpu.cpuInfo(function(error, results) {
@@ -224,28 +200,28 @@
      *      console.log('Installed Processors: ', results);
      * });
      */
-    exports.cpuInfo = function cpuInfo(cb) {
-        if(!isFunction(cb)) cb = emptyFn;
-        if(!checkPlatform(cb)) return;
-        
-        execFile(wmic, ['cpu', 'get', 'Name'], function (error, res, stderr) {
+    cpuInfo(cb) {
+        execFile(wmic, ['cpu', 'get', 'Name'], function(error, res, stderr) {
             if(error !== null || stderr) return cb(error || stderr);
             
-            var cpus = res.match(/[^\r\n]+/g).map(function(v) {
+            let cpus = res.match(/[^\r\n]+/g).map(function(v) {
                 return v.trim();
             });
             
             cpus.shift();
             cb(null, cpus);
         });
-    };
-
+        
+        return this;
+    }
+    
     /**
-     * Gets the total memory usage value in KB , MB and GB .
-     * @param {function} cb A callback function to handle the result (error, results).
+     * Gets the total memory usage on the machine in KB, MB and GB.
+     * @param  {Function} cb Callback to call with results (error, results)
+     * @return {WindowsCPU}  Instance of the WindowsCPU class
      * @example
      *
-     * var cpu = require('windows-cpu');
+     * const cpu = require('windows-cpu');
      *
      * // Get the memory usage
      * cpu.totalMemoryUsage(function(error, results) {
@@ -263,17 +239,14 @@
      *      console.log('Total Memory Usage: ', result);
      * });
      */
-    exports.totalMemoryUsage = function totalMemoryUsage(cb) {
-        if (!isFunction(cb)) cb = emptyFn;
-        if (!checkPlatform(cb)) return;
-        
-        var cmd = "tasklist /FO csv /nh";
-        exec(cmd, function (error, res, stderr) {
+    totalMemoryUsage(cb) {
+        let cmd = 'tasklist /FO csv /nh';
+        exec(cmd, function(error, res, stderr) {
             if(error !== null || stderr) return cb(error || stderr);
-            var results = { usageInKb: 0 , usageInMb: 0 , usageInGb: 0 };
+            let results = { usageInKb: 0 , usageInMb: 0 , usageInGb: 0 };
             
             results.usageInKb = res.match(/[^\r\n]+/g).map(function(v) {
-                var amt = +v.split('","')[4].replace(/[^\d]/g, '');
+                let amt = +v.split('","')[4].replace(/[^\d]/g, '');
                 return (!isNaN(amt) && typeof amt === 'number')? amt : 0;
             }).reduce(function(prev, current) {
                 return prev + current;
@@ -284,5 +257,9 @@
             
             cb(null, results);
         });
-    };
-}());
+        
+        return this;
+    }
+}
+
+module.exports = new WindowsCPU();
path: index.js