Step 10 - Putting it all together: the taint tracking query
github-learning-lab opened this issue ยท 2 comments
Step 10: Putting it all together
Great! you made it to the final step ๐
We have now identified
- (a) places in the program which receive jQuery plugin options, and which may be considered as sources of untrusted data, and
- (b) places in the program which are passed to the jQuery
$
function and may be interpreted as HTML, that we consider as sinks, in the sense that they will perform actions with the data they receive. We don't want these sinks to receive untrusted data.
We now want to tie these two together to ask: does the untrusted data from a jQuery plugin option ever flow to the potentially unsafe $
call?
This is also a data flow problem. However, it is larger in scope that the problems we have tackled so far, because the plugin options and the $
call may be in different functions. We call this a global data flow problem.
๐ You can learn more about data flow analysis in JavaScript by reading the documentation and this cheat sheet.
In this section we will create a path problem query capable of looking for global data flow, by populating this template:
/**
* @name Cross-site scripting vulnerable plugin
* @kind path-problem
* @id js/xss-unsafe-plugin
*/
import javascript
import DataFlow::PathGraph
class Config extends TaintTracking::Configuration {
Config() { this = "Config" }
override predicate isSource(DataFlow::Node source) {
/** TODO fill me in from step 9 **/
}
override predicate isSink(DataFlow::Node sink) {
sink = /** TODO fill me in from step 5 **/
}
}
from Config config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink, source, sink, "Potential XSS vulnerability in plugin."
In this template, we just have to define what are the sources and the sinks that we want to consider, and the CodeQL global data flow library will give us all the paths where data can flow from these sources to these sinks, using the predicate hasFlowPath
that holds true when tainted data from a given source flows to a sink.
โจ๏ธ Finish line! The final taint tracking query
Edit the file final.ql
and paste the below template:
/**
* @name Cross-site scripting vulnerable plugin
* @kind path-problem
* @id js/xss-unsafe-plugin
*/
import javascript
import DataFlow::PathGraph
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "XssUnsafeJQueryPlugin" }
override predicate isSource(DataFlow::Node source) {
// Fill me in from Step 9
}
override predicate isSink(DataFlow::Node sink) {
sink = // Fill me in from Step 5
}
}
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink, source, sink, "Potential XSS vulnerability in plugin."
- Replace the first
TODO
with the definition ofisSource
that you wrote in step 9. - We identified the sinks to be the first argument of a call to
$
. Use your step 5 query to replace the secondTODO
.
This final query should find 5 results in the unpatched Bootstrap codebase. You can browse the results to check that some of them are indeed real vulnerabilities.
Submit your query when you're happy with the results.
Congratulations, you have finished the course!
What's next?
- Read the tutorial on analyzing data flow in JavaScript and TypeScript.
- Explore the open-source CodeQL queries and libraries, and learn how to contribute a new query.
- Visit the GitHub Security Lab website
- Try out the CodeQL Capture-the-Flag challenges.
- Read about more vulnerabilities found using CodeQL on the GitHub Security Lab research blog.
- Get bounty rewards for contributing to securing open source by writing CodeQL queries.