codeql
codeql copied to clipboard
CodeQL unable to find out sources of a chosen dataflow node in Javascript
Hi, for the following snippet i'm interested in finding out what nodes flow to s + c node.
function main() {
let s = window.location;
let c = "";
let input = s + c;
eval(input);
}
By looking at the snippet, the answer clearly consists of five dataflow nodes. s + c itself, c , "" , s , window.location.
The followings are methods i tried so far.
CodeQL query for locating s + c explicitly by providing location
import javascript
class SinkNode extends DataFlow::Node {
SinkNode() {
exists(DataFlow::Node node |
node.hasLocationInfo("filepath to the snippet",
4, 15, 4, 19) and
this = node
)
}
}
class TestSucessor extends DataFlow::Node {
TestSucessor() {
exists(DataFlow::Node node |
node instanceof Sink and
exists(DataFlow::Node source |
source.getASuccessor*() = node and
this = source
)
)
}
}
This would only mark s + c as a predecessor.
class TestPredecessor extends DataFlow::Node {
TestPredecessor() {
exists(DataFlow::Node node |
node instanceof Sink and
this = node.getAPredecessor*()
)
}
}
This would only mark s + c as a predecessor.
class TestLocalSource extends DataFlow::Node {
TestLocalSource() {
exists(DataFlow::Node node |
this = node.getALocalSource*() and
node instanceof Sink
)
}
}
class TestLocalUse extends DataFlow::SourceNode {
TestLocalUse() {
exists(DataFlow::SourceNode src |
exists(DataFlow::Node node |
node instanceof Sink and
src.getALocalUse() = node and
this = src
)
)
}
}
Neither mark anything out.
I would see that an overkill for this issue is simply using tainted analysis. Mark s+c as sink and use any() for the source. However, i want to keep it simple. Any idea how to do it simply?
Many thanks.
Hi @lllssskkk 👋🏻
Thanks for the question! Firstly, the simplest option for finding the add expression would be:
from AddExpr e, DataFlow::Node addNode
where addNode.asExpr() = e
select e, addNode
Beyond that, you will need taint tracking for this, because the AddExpr combines s and c into a new value. So, therefore, the data flow node represented by addNode above is a different value than s and c and so data flow alone is not enough. For example, the following configuration gives me results as expected:
import javascript
module MyAnalysisConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) { any() }
predicate isSink(DataFlow::Node node) { exists(AddExpr e | e = node.asExpr()) }
}
module MyAnalysisFlow = TaintTracking::Global<MyAnalysisConfig>;
from DataFlow::Node source, DataFlow::Node sink
where MyAnalysisFlow::flow(source, sink)
select source, sink