CVE-2022-25926: Other (NVD-CWE-Other)
value: Versions of the package window-control before 1.4.5 are vulnerable to Command Injection via the sendKeys function, due to improper input sanitization.
CWE description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
CVSS v3 base score: 7.8
Published: 2023-01-04T18:15Z
Repository: https://github.com/bruno-robert/window-control
Language: JSON
Files changed: index.js, package-lock.json, package.json
Commit date: 2023-01-02 15:24:07 +0100
Commit message: fix: add sanitisation to user input

Diff: diff --git a/index.js b/index.js
index 3502c4f..845f3b8 100644
--- a/index.js
+++ b/index.js
@@ -13,10 +13,16 @@ const winSendKeysToWindowName = path.join(__dirname, 'windows', 'sendKeys.bat')
 
 const linuxGetWindowList = path.join(__dirname, 'linux', 'getWindowList.sh')
 const macGetWindowList = path.join(__dirname, 'mac', 'getWindowList.applescript')
 const winGetWindowList = path.join(__dirname, 'windows', 'listOpenWindows.bat')
 
+const sanitiseUserInput = (input) => {
+  let newInput = (' ' + input).slice(1)
+  newInput = newInput.replaceAll("'", "");
+  return newInput
+}
+
 /**
  * Focuses the first window of the process with the PID given
  * @param {integer} id PID to use to find the application window
  * @param {function} callback callback, get error and message as parameters
  */
@@ -61,11 +67,11 @@ const focusWindow = (id, callback) => {
 const sendKeys = (id, keys, {resetFocus = false, pressEnterOnceDone = true} = {}) => {
   let execPromise = new Promise((resolve, reject) => {
     keys = keys.replace('"', '\\"')
 
     if ( process.platform === 'darwin' ) {
-      exec(`osascript "${macFocusAndSendKeys}" ${id} "${keys}" ${resetFocus} ${pressEnterOnceDone}`, (error, stdout, stderr) => {
+      exec(`osascript "${macFocusAndSendKeys}" '${sanitiseUserInput(id)}' '${sanitiseUserInput(keys)}' ${resetFocus} ${pressEnterOnceDone}`, (error, stdout, stderr) => {
         if (error) reject(error)
         if (stderr) reject(stderr)
         resolve(stdout)
       })
 
@@ -74,21 +80,21 @@ const sendKeys = (id, keys, {resetFocus = false, pressEnterOnceDone = true} = {}
       const windowTitle = id
       if (pressEnterOnceDone) {
         keys = keys + '~'
       }
 
-      exec(`${winSendKeysToWindowName} "${windowTitle}" "${keys}"`, (error, stdout, stderr) => {
+      exec(`${winSendKeysToWindowName} '${sanitiseUserInput(windowTitle)}' '${sanitiseUserInput(keys)}'`, (error, stdout, stderr) => {
         if (error) reject(error)
         if (stderr) reject(stderr)
         resolve(stdout)
       })
       
     } else if ( process.platform === 'linux' ) {
       // TODO: add option to reset focus on linux
       // TODO: add option to not press enter once keys have been sent
       const windowID = id // although the function calls it pid, iin this case it's a windowID
-      exec(`${sendTextToWindowWithId} ${windowID} "${keys}"`, (error, stdout, stderr) => {
+      exec(`${sendTextToWindowWithId} '${sanitiseUserInput(windowID)}' '${sanitiseUserInput(keys)}'`, (error, stdout, stderr) => {
         if (error) reject(error)
         if (stderr) reject(stderr)
         resolve(stdout)
       })
 
@@ -197,6 +203,6 @@ const getWindowList = () => {
 
 module.exports = {
   focusWindow: focusWindow,
   sendKeys: sendKeys,
   getWindowList: getWindowList,
-}
\ No newline at end of file
+}
diff --git a/package-lock.json b/package-lock.json
index 9cedf34..7f88625 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,10 +1,56 @@
 {
   "name": "window-control",
-  "version": "1.4.4",
-  "lockfileVersion": 1,
+  "version": "1.4.5",
+  "lockfileVersion": 2,
   "requires": true,
+  "packages": {
+    "": {
+      "name": "window-control",
+      "version": "1.4.5",
+      "license": "MIT",
+      "dependencies": {
+        "hazardous": "^0.3.0",
+        "json5": "^2.1.1"
+      }
+    },
+    "node_modules/callsite": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
+      "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/hazardous": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/hazardous/-/hazardous-0.3.0.tgz",
+      "integrity": "sha512-VLSlBMoLTnfScKBJTycufZ2OHLO06eS3Q0mxNdHJ+egd1QLqeLitxDeGeUuoIgOqSPer+uqZCxiv43a1EVmwdg==",
+      "dependencies": {
+        "callsite": "^1.0.0"
+      }
+    },
+    "node_modules/json5": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz",
+      "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==",
+      "dependencies": {
+        "minimist": "^1.2.0"
+      },
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+      "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
+    }
+  },
   "dependencies": {
     "callsite": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
       "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
diff --git a/package.json b/package.json
index 6937e33..f902f39 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
 {
   "name": "window-control",
-  "version": "1.4.4",
+  "version": "1.4.5",
   "description": "Tools to manage window focus on mac, windows and linux",
   "main": "index.js",
   "scripts": {
     "test": "echo \"Error: no test specified\""
   },

Vulnerable code:       exec(`osascript "${macFocusAndSendKeys}" ${id} "${keys}" ${resetFocus} ${pressEnterOnceDone}`, (error, stdout, stderr) => {
      exec(`${winSendKeysToWindowName} "${windowTitle}" "${keys}"`, (error, stdout, stderr) => {
      exec(`${sendTextToWindowWithId} ${windowID} "${keys}"`, (error, stdout, stderr) => {
}
  "version": "1.4.4",
  "lockfileVersion": 1,
  "version": "1.4.4",
Fixed code: const sanitiseUserInput = (input) => {
  let newInput = (' ' + input).slice(1)
  newInput = newInput.replaceAll("'", "");
  return newInput
}

      exec(`osascript "${macFocusAndSendKeys}" '${sanitiseUserInput(id)}' '${sanitiseUserInput(keys)}' ${resetFocus} ${pressEnterOnceDone}`, (error, stdout, stderr) => {
      exec(`${winSendKeysToWindowName} '${sanitiseUserInput(windowTitle)}' '${sanitiseUserInput(keys)}'`, (error, stdout, stderr) => {
      exec(`${sendTextToWindowWithId} '${sanitiseUserInput(windowID)}' '${sanitiseUserInput(keys)}'`, (error, stdout, stderr) => {
}
  "version": "1.4.5",
  "lockfileVersion": 2,
  "packages": {
    "": {
      "name": "window-control",
      "version": "1.4.5",
      "license": "MIT",
      "dependencies": {
        "hazardous": "^0.3.0",
        "json5": "^2.1.1"
      }
    },
    "node_modules/callsite": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
      "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
      "engines": {
        "node": "*"
      }
    },
    "node_modules/hazardous": {
      "version": "0.3.0",
      "resolved": "https://registry.npmjs.org/hazardous/-/hazardous-0.3.0.tgz",
      "integrity": "sha512-VLSlBMoLTnfScKBJTycufZ2OHLO06eS3Q0mxNdHJ+egd1QLqeLitxDeGeUuoIgOqSPer+uqZCxiv43a1EVmwdg==",
      "dependencies": {
        "callsite": "^1.0.0"
      }
    },
    "node_modules/json5": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz",
      "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==",
      "dependencies": {
        "minimist": "^1.2.0"
      },
      "bin": {
        "json5": "lib/cli.js"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/minimist": {
      "version": "1.2.6",
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
      "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
    }
  },
  "version": "1.4.5",