JS: removed execa parts from SystemCommandExecutors and moved it to Execa.qll

This commit is contained in:
Napalys Klicius
2025-06-24 12:41:22 +02:00
parent 0902ca0605
commit 79a9d7def8
2 changed files with 85 additions and 13 deletions

View File

@@ -58,6 +58,9 @@ module Execa {
or
this = API::moduleImport("execa").getMember("execaSync").getACall() and
isSync = true
or
this = API::moduleImport("execa").getACall() and
isSync = false
}
}
@@ -208,4 +211,86 @@ module Execa {
private predicate isExecaShellEnable(API::Node n) {
n.getMember("shell").asSink().asExpr().(BooleanLiteral).getValue() = "true"
}
/**
* A call to `execa.node`
*/
class ExecaNodeCall extends SystemCommandExecution, API::CallNode {
ExecaNodeCall() { this = API::moduleImport("execa").getMember("node").getACall() }
override DataFlow::Node getACommandArgument() { result = this.getArgument(0) }
override predicate isShellInterpreted(DataFlow::Node arg) { none() }
override DataFlow::Node getArgumentList() {
result = this.getArgument(1) and
not result.asExpr() instanceof ObjectExpr
}
override predicate isSync() { none() }
override DataFlow::Node getOptionsArg() {
result = this.getLastArgument() and
result.asExpr() instanceof ObjectExpr
}
}
/**
* A call to `execa.stdout`, `execa.stderr`, or `execa.sync`
*/
class ExecaStreamCall extends SystemCommandExecution, API::CallNode {
string methodName;
ExecaStreamCall() {
methodName in ["stdout", "stderr", "sync"] and
this = API::moduleImport("execa").getMember(methodName).getACall()
}
override DataFlow::Node getACommandArgument() { result = this.getArgument(0) }
override predicate isShellInterpreted(DataFlow::Node arg) {
arg = this.getArgument(0) and
isExecaShellEnable(this.getParameter([1, 2]))
}
override DataFlow::Node getArgumentList() {
result = this.getArgument(1) and
not result.asExpr() instanceof ObjectExpr
}
override predicate isSync() { methodName = "sync" }
override DataFlow::Node getOptionsArg() {
result = this.getLastArgument() and
result.asExpr() instanceof ObjectExpr
}
}
/**
* A call to `execa.shell` or `execa.shellSync`
*/
class ExecaShellCall extends SystemCommandExecution, API::CallNode {
boolean sync;
ExecaShellCall() {
this = API::moduleImport("execa").getMember("shell").getACall() and
sync = false
or
this = API::moduleImport("execa").getMember("shellSync").getACall() and
sync = true
}
override DataFlow::Node getACommandArgument() { result = this.getArgument(0) }
override predicate isShellInterpreted(DataFlow::Node arg) { arg = this.getACommandArgument() }
override DataFlow::Node getArgumentList() { none() }
override predicate isSync() { sync = true }
override DataFlow::Node getOptionsArg() {
result = this.getArgument(1) and
result.asExpr() instanceof ObjectExpr
}
}
}

View File

@@ -16,17 +16,6 @@ private predicate execApi(
cmdArg = 0 and
shell = false and
optionsArg = -1
or
mod = "execa" and
optionsArg = -1 and
(
shell = false and
fn = ["node", "stdout", "stderr", "sync"]
or
shell = true and
fn = ["command", "commandSync", "shell", "shellSync"]
) and
cmdArg = 0
)
}
@@ -38,8 +27,6 @@ private predicate execApi(string mod, int cmdArg, int optionsArg, boolean shell)
mod = "cross-spawn-async" and cmdArg = 0 and optionsArg = -1
or
mod = "exec-async" and cmdArg = 0 and optionsArg = -1
or
mod = "execa" and cmdArg = 0 and optionsArg = -1
)
or
shell = true and