JS: Model consolidate and factor in template syntax from call site

This commit is contained in:
Asger Feldthaus
2021-07-26 10:01:21 +02:00
parent 425bd7abf9
commit 14bada4bbe
6 changed files with 103 additions and 0 deletions

View File

@@ -190,6 +190,15 @@ module Templating {
TemplateFile getTemplateFile() {
result = getTemplateFileNode().(TemplateFileReference).getTemplateFile()
}
/**
* Gets the template syntax used by this template instantiation, if known.
*
* If not known, the relevant syntax will be determined by a heuristic.
*/
TemplateSyntax getTemplateSyntax() {
result = range.getTemplateSyntax()
}
}
/** Companion module to the `TemplateInstantiation` class. */
@@ -206,6 +215,13 @@ module Templating {
/** Gets a data flow node that refers to an object whose properties become variables in the template. */
abstract DataFlow::Node getTemplateParamsNode();
/**
* Gets the template syntax used by this template instantiation, if known.
*
* If not known, the relevant syntax will be determined by a heuristic.
*/
TemplateSyntax getTemplateSyntax() { none() }
}
}
@@ -558,12 +574,20 @@ module Templating {
result = getTemplateSyntaxInFolder(f.getParentContainer())
}
private TemplateSyntax getTemplateSyntaxFromInstantiation(TemplateFile file) {
result = any(TemplateInstantiaton inst | inst.getTemplateFile() = file).getTemplateSyntax()
}
/**
* Gets a template syntax likely to be used in the given file.
*/
TemplateSyntax getLikelyTemplateSyntax(TemplateFile file) {
result = getTemplateSyntaxFromInstantiation(file)
or
not exists(getTemplateSyntaxFromInstantiation(file)) and
result.getAFileExtension() = file.getExtension()
or
not exists(getTemplateSyntaxFromInstantiation(file)) and
not file.getExtension() = any(TemplateSyntax s).getAFileExtension() and
result = getTemplateSyntaxInFolder(file.getParentContainer())
}
@@ -656,4 +680,38 @@ module Templating {
result = tag.getFile().getParentContainer()
}
}
/**
* A call to a member of the `consolidate` library, seen as a template instantiation.
*/
private class ConsolidateCall extends TemplateInstantiaton::Range, API::CallNode {
string engine;
ConsolidateCall() {
this = API::moduleImport("consolidate").getMember(engine).getACall()
}
override TemplateSyntax getTemplateSyntax() {
result.getAPackageName() = engine
}
override DataFlow::SourceNode getOutput() {
result = getParameter([1, 2]).getParameter(1).getAnImmediateUse()
or
not exists(getParameter([1, 2]).getParameter(1)) and
result = this
}
override DataFlow::Node getTemplateFileNode() {
result = getArgument(0)
}
override DataFlow::Node getTemplateContentNode() {
none()
}
override DataFlow::Node getTemplateParamsNode() {
result = getArgument(1)
}
}
}

View File

@@ -0,0 +1,4 @@
import * as consolidate from 'consolidate';
consolidate.ejs('views/instantiated_as_ejs.html', { data: 123 }, (err, html) => {});
consolidate.handlebars('views/instantiated_as_hbs.html', { data: 123 }, (err, html) => {});

View File

@@ -0,0 +1,9 @@
getTemplateInstantiationSyntax
| consolidate.js:3:1:3:83 | consoli ... => {}) | ejs |
| consolidate.js:4:1:4:90 | consoli ... => {}) | mustache |
getLikelyTemplateSyntax
| views/instantiated_as_ejs.html:0:0:0:0 | views/instantiated_as_ejs.html | ejs |
| views/instantiated_as_hbs.html:0:0:0:0 | views/instantiated_as_hbs.html | mustache |
xssSink
| views/instantiated_as_ejs.html:4:9:4:23 | <%- xss_sink %> |
| views/instantiated_as_hbs.html:7:9:7:24 | {{{ xss_sink }}} |

View File

@@ -0,0 +1,14 @@
import javascript
import semmle.javascript.security.dataflow.Xss
query Templating::TemplateSyntax getTemplateInstantiationSyntax(Templating::TemplateInstantiaton inst) {
result = inst.getTemplateSyntax()
}
query Templating::TemplateSyntax getLikelyTemplateSyntax(Templating::TemplateFile file) {
result = Templating::getLikelyTemplateSyntax(file)
}
query DomBasedXss::Sink xssSink() {
any()
}

View File

@@ -0,0 +1,9 @@
<html>
<body>
<%= safe %>
<%- xss_sink %>
{{ safe }}
{{{ safe }}}
</body>
</html>

View File

@@ -0,0 +1,9 @@
<html>
<body>
<%= safe %>
<%- safe %>
{{ safe }}
{{{ xss_sink }}}
</body>
</html>