Harmoc/codeql-javascript-unsafe-jquery-plugin

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."
  1. Replace the first TODO with the definition of isSource that you wrote in step 9.
  2. We identified the sinks to be the first argument of a call to $. Use your step 5 query to replace the second TODO.

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?