diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll b/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll index 33fbef3cf3e7..9f3eeb6e0dc9 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll @@ -1,15 +1,29 @@ /** * Models the `shelljs` library in terms of `FileSystemAccess` and `SystemCommandExecution`. + * + * https://www.npmjs.com/package/shelljs */ import javascript module ShellJS { + private API::Node shellJSMember() { + result = API::moduleImport("shelljs") + or + result = + shellJSMember() + .getMember([ + "exec", "cd", "cp", "touch", "chmod", "pushd", "find", "ls", "ln", "mkdir", "mv", + "rm", "cat", "head", "sort", "tail", "uniq", "grep", "sed", "to", "toEnd", "echo" + ]) + .getReturn() + } + /** - * Gets an import of the `shelljs` or `async-shelljs` module. + * Gets a function that can execute a shell command using the `shelljs` or `async-shelljs` modules. */ DataFlow::SourceNode shelljs() { - result = DataFlow::moduleImport("shelljs") or + result = shellJSMember().asSource() or result = DataFlow::moduleImport("async-shelljs") } @@ -39,7 +53,10 @@ module ShellJS { /** The `shelljs.exec` library modeled as a `shelljs` member. */ private class ShellJsExec extends Range { - ShellJsExec() { this = DataFlow::moduleImport("shelljs.exec") } + ShellJsExec() { + this = DataFlow::moduleImport("shelljs.exec") or + this = shellJSMember().getMember("exec").asSource() + } override string getName() { result = "exec" } } diff --git a/javascript/ql/test/library-tests/frameworks/Shelljs/ShellJS.expected b/javascript/ql/test/library-tests/frameworks/Shelljs/ShellJS.expected index 4c8f45af1c01..003ae3f442f8 100644 --- a/javascript/ql/test/library-tests/frameworks/Shelljs/ShellJS.expected +++ b/javascript/ql/test/library-tests/frameworks/Shelljs/ShellJS.expected @@ -52,9 +52,14 @@ test_FileSystemAccess | tst.js:56:1:56:18 | shelljs.uniq(file) | | tst.js:57:1:57:26 | shelljs ... file2) | | tst.js:58:1:58:32 | shelljs ... file2) | +| tst.js:60:1:60:17 | shelljs.cat(file) | +| tst.js:60:1:60:41 | shelljs ... cement) | +| tst.js:61:1:61:17 | shelljs.cat(file) | test_MissingFileSystemAccess test_SystemCommandExecution | tst.js:14:1:14:27 | shelljs ... ts, cb) | +| tst.js:60:1:60:51 | shelljs ... ec(cmd) | +| tst.js:61:1:61:27 | shelljs ... ec(cmd) | test_FileNameSource | tst.js:15:1:15:26 | shelljs ... file2) | | tst.js:24:1:24:16 | shelljs.ls(file) | diff --git a/javascript/ql/test/library-tests/frameworks/Shelljs/tst.js b/javascript/ql/test/library-tests/frameworks/Shelljs/tst.js index feb7c7affa52..9e7905c98477 100644 --- a/javascript/ql/test/library-tests/frameworks/Shelljs/tst.js +++ b/javascript/ql/test/library-tests/frameworks/Shelljs/tst.js @@ -56,3 +56,6 @@ shelljs.touch(file1, file2); shelljs.uniq(file); shelljs.uniq(file1, file2); shelljs.uniq(opts, file1, file2); + +shelljs.cat(file).sed(regex, replacement).exec(cmd); +shelljs.cat(file).exec(cmd);