From f1a7f0a7e83f7bc65dc4cef93a23bf71b9d8a564 Mon Sep 17 00:00:00 2001 From: amammad Date: Fri, 22 Sep 2023 19:21:41 +1000 Subject: [PATCH 1/2] V1 --- .../semmle/javascript/frameworks/ShellJS.qll | 21 +++++++++++++++++-- .../frameworks/Shelljs/ShellJS.expected | 5 +++++ .../library-tests/frameworks/Shelljs/tst.js | 3 +++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll b/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll index 33fbef3cf3e7..0d68fda01ab8 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 { + 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. */ 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); From 42a9962519e06831b1fb0388c26474c85882c792 Mon Sep 17 00:00:00 2001 From: am0o0 <77095239+am0o0@users.noreply.github.com> Date: Thu, 16 May 2024 14:05:06 +0200 Subject: [PATCH 2/2] make shellJSMember predicate private, improve predicate document --- javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll b/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll index 0d68fda01ab8..9f3eeb6e0dc9 100644 --- a/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll +++ b/javascript/ql/lib/semmle/javascript/frameworks/ShellJS.qll @@ -7,7 +7,7 @@ import javascript module ShellJS { - API::Node shellJSMember() { + private API::Node shellJSMember() { result = API::moduleImport("shelljs") or result = @@ -20,7 +20,7 @@ module ShellJS { } /** - * 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 = shellJSMember().asSource() or