mirror of
https://github.com/tiddly-gittly/TidGi-Desktop.git
synced 2025-12-06 02:30:47 -08:00
83 lines
2.4 KiB
Text
83 lines
2.4 KiB
Text
/**
|
|
* @name Unsafe use of Function constructor with user input
|
|
* @description Detects Function constructor calls with potentially tainted template strings
|
|
* @kind path-problem
|
|
* @problem.severity error
|
|
* @security-severity 9.0
|
|
* @precision high
|
|
* @id tidgi/new-function-injection
|
|
* @tags security
|
|
* external/cwe/cwe-094
|
|
*/
|
|
|
|
import javascript
|
|
import DataFlow::PathGraph
|
|
|
|
/**
|
|
* A call to the Function constructor
|
|
*/
|
|
class FunctionConstructorCall extends DataFlow::NewNode {
|
|
FunctionConstructorCall() {
|
|
this.getCalleeName() = "Function"
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Configuration for tracking unsafe Function constructor usage
|
|
*/
|
|
class FunctionConstructorInjectionConfig extends TaintTracking::Configuration {
|
|
FunctionConstructorInjectionConfig() {
|
|
this = "FunctionConstructorInjectionConfig"
|
|
}
|
|
|
|
override predicate isSource(DataFlow::Node source) {
|
|
// Function parameters
|
|
source.asExpr() instanceof Parameter or
|
|
// Object property access
|
|
source instanceof DataFlow::PropRead or
|
|
// IPC message handlers
|
|
exists(DataFlow::CallNode call |
|
|
(call.getCalleeName() = "on" or call.getCalleeName() = "handle") and
|
|
source = call.getCallback([0..1]).getParameter([0..2])
|
|
)
|
|
}
|
|
|
|
override predicate isSink(DataFlow::Node sink) {
|
|
exists(FunctionConstructorCall fnCall |
|
|
sink = fnCall.getAnArgument()
|
|
)
|
|
}
|
|
|
|
override predicate isSanitizer(DataFlow::Node node) {
|
|
// JSON.parse/stringify are safe
|
|
exists(DataFlow::CallNode call |
|
|
call = DataFlow::globalVarRef("JSON").getAMemberCall(["stringify", "parse"]) and
|
|
node = call
|
|
) or
|
|
// Whitelist validation
|
|
exists(DataFlow::MethodCallNode test |
|
|
test.getMethodName() = "test" and
|
|
test.getReceiver().asExpr() instanceof RegExpLiteral and
|
|
node = test
|
|
)
|
|
}
|
|
|
|
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
|
|
// Template string interpolation
|
|
exists(TemplateLiteral tl |
|
|
pred.asExpr() = tl.getAnElement() and
|
|
succ.asExpr() = tl
|
|
) or
|
|
// String concatenation
|
|
exists(AddExpr add |
|
|
pred.asExpr() = add.getAnOperand() and
|
|
succ.asExpr() = add
|
|
)
|
|
}
|
|
}
|
|
|
|
from FunctionConstructorInjectionConfig config, DataFlow::PathNode source, DataFlow::PathNode sink
|
|
where config.hasFlowPath(source, sink)
|
|
select sink.getNode(), source, sink,
|
|
"Potential code injection via Function constructor: user input $@ flows into dynamically created function",
|
|
source.getNode(), "here"
|