Skip to content

Commit d782bd9

Browse files
authored
Merge pull request github#13624 from jorgectf/seclab/dotjs
JS: Add `dot.js` support
2 parents a1036c8 + fe3e768 commit d782bd9

File tree

9 files changed

+69
-4
lines changed

9 files changed

+69
-4
lines changed

javascript/extractor/src/com/semmle/js/extractor/AutoBuild.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@
153153
* <li>All JavaScript files, that is, files with one of the extensions supported by {@link
154154
* FileType#JS} (currently ".js", ".jsx", ".mjs", ".cjs", ".es6", ".es").
155155
* <li>All HTML files, that is, files with with one of the extensions supported by {@link
156-
* FileType#HTML} (currently ".htm", ".html", ".xhtm", ".xhtml", ".vue", ".html.erb", ".jsp").
156+
* FileType#HTML} (currently ".htm", ".html", ".xhtm", ".xhtml", ".vue", ".html.erb", ".html.dot", ".jsp").
157157
* <li>All YAML files, that is, files with one of the extensions supported by {@link
158158
* FileType#YAML} (currently ".raml", ".yaml", ".yml").
159159
* <li>Files with base name "package.json" or "tsconfig.json", and files whose base name

javascript/extractor/src/com/semmle/js/extractor/FileExtractor.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ private static int skipBOM(byte[] bytes, int length) {
103103

104104
/** Information about supported file types. */
105105
public static enum FileType {
106-
HTML(".htm", ".html", ".xhtm", ".xhtml", ".vue", ".hbs", ".ejs", ".njk", ".erb", ".jsp") {
106+
HTML(".htm", ".html", ".xhtm", ".xhtml", ".vue", ".hbs", ".ejs", ".njk", ".erb", ".jsp", ".dot") {
107107
@Override
108108
public IExtractor mkExtractor(ExtractorConfig config, ExtractorState state) {
109109
return new HTMLExtractor(config, state);
@@ -125,6 +125,12 @@ protected boolean contains(File f, String lcExt, ExtractorConfig config) {
125125
return false;
126126
}
127127
}
128+
// for DOT files we are only interrested in `.html.dot` files
129+
if (FileUtil.extension(f).equalsIgnoreCase(".dot")) {
130+
if (!f.getName().toLowerCase().endsWith(".html.dot")) {
131+
return false;
132+
}
133+
}
128134
return super.contains(f, lcExt, config);
129135
}
130136
},

javascript/extractor/src/com/semmle/js/extractor/TemplateEngines.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88

99
public class TemplateEngines {
1010
private static final String MUSTACHE_TAG_TRIPLE = "\\{\\{\\{[~]?(.*?)[~]?\\}\\}\\}"; // {{{ x }}}
11-
private static final String MUSTACHE_TAG_DOUBLE = "\\{\\{(?!\\{)[~&]?(.*?)[~]?\\}\\}"; // {{ x }}}
11+
private static final String MUSTACHE_TAG_DOUBLE = "\\{\\{(?!\\{)[~&!=]?(.*?)[~]?\\}\\}"; // {{ x }}}
1212
private static final String MUSTACHE_TAG_PERCENT = "\\{%(?!>)(.*?)%\\}"; // {% x %}
1313
private static final String EJS_TAG = "<%(?![%<>}])[-=]?(.*?)[_-]?%>"; // <% x %>
1414

1515
/** Pattern for a template tag whose contents should be parsed as an expression */
1616
public static final Pattern TEMPLATE_EXPR_OPENING_TAG =
17-
Pattern.compile("^(?:\\{\\{\\{?|<%[-=])"); // {{, {{{, <%=, <%-
17+
Pattern.compile("^(?:\\{\\{[{!]?|<%[-=])"); // {{, {{{, {{!, <%=, <%-
1818

1919
/**
2020
* Pattern matching a template tag from a supported template engine.

javascript/ql/lib/semmle/javascript/frameworks/Templating.qll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,22 @@ module Templating {
580580
override string getAPackageName() { result = "ejs" }
581581
}
582582

583+
/**
584+
* doT-style syntax, using `{{! }}` for safe interpolation, and `{{= }}` for
585+
* unsafe interpolation.
586+
*/
587+
private class DotStyleSyntax extends TemplateSyntax {
588+
DotStyleSyntax() { this = "dot" }
589+
590+
override string getRawInterpolationRegexp() { result = "(?s)\\{\\{!(.*?)\\}\\}" }
591+
592+
override string getEscapingInterpolationRegexp() { result = "(?s)\\{\\{=(.*?)\\}\\}" }
593+
594+
override string getAFileExtension() { result = "dot" }
595+
596+
override string getAPackageName() { result = "dot" }
597+
}
598+
583599
private TemplateSyntax getOwnTemplateSyntaxInFolder(Folder f) {
584600
exists(PackageDependencies deps |
585601
deps.getADependency(result.getAPackageName(), _) and
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added support for [doT](https://github.com/olado/doT) templates.

javascript/ql/test/library-tests/frameworks/Templating/Xss.expected

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ nodes
5050
| app.js:66:18:66:34 | req.query.rawHtml |
5151
| app.js:66:18:66:34 | req.query.rawHtml |
5252
| app.js:66:18:66:34 | req.query.rawHtml |
53+
| app.js:73:18:73:30 | req.query.foo |
54+
| app.js:73:18:73:30 | req.query.foo |
55+
| app.js:73:18:73:30 | req.query.foo |
5356
| projectA/src/index.js:6:38:6:53 | req.query.taintA |
5457
| projectA/src/index.js:6:38:6:53 | req.query.taintA |
5558
| projectA/src/index.js:6:38:6:53 | req.query.taintA |
@@ -144,6 +147,11 @@ nodes
144147
| views/angularjs_sinks.ejs:4:9:4:22 | <%- rawHtml %> |
145148
| views/angularjs_sinks.ejs:4:13:4:19 | rawHtml |
146149
| views/angularjs_sinks.ejs:4:13:4:19 | rawHtml |
150+
| views/dot_sinks.html.dot:3:9:3:22 | {{! tainted }} |
151+
| views/dot_sinks.html.dot:3:9:3:22 | {{! tainted }} |
152+
| views/dot_sinks.html.dot:3:9:3:22 | {{! tainted }} |
153+
| views/dot_sinks.html.dot:3:13:3:19 | tainted |
154+
| views/dot_sinks.html.dot:3:13:3:19 | tainted |
147155
| views/ejs_include1.ejs:1:1:1:10 | <%- foo %> |
148156
| views/ejs_include1.ejs:1:1:1:10 | <%- foo %> |
149157
| views/ejs_include1.ejs:1:1:1:10 | <%- foo %> |
@@ -367,6 +375,10 @@ edges
367375
| app.js:66:18:66:34 | req.query.rawHtml | views/angularjs_sinks.ejs:4:13:4:19 | rawHtml |
368376
| app.js:66:18:66:34 | req.query.rawHtml | views/angularjs_sinks.ejs:4:13:4:19 | rawHtml |
369377
| app.js:66:18:66:34 | req.query.rawHtml | views/angularjs_sinks.ejs:4:13:4:19 | rawHtml |
378+
| app.js:73:18:73:30 | req.query.foo | views/dot_sinks.html.dot:3:13:3:19 | tainted |
379+
| app.js:73:18:73:30 | req.query.foo | views/dot_sinks.html.dot:3:13:3:19 | tainted |
380+
| app.js:73:18:73:30 | req.query.foo | views/dot_sinks.html.dot:3:13:3:19 | tainted |
381+
| app.js:73:18:73:30 | req.query.foo | views/dot_sinks.html.dot:3:13:3:19 | tainted |
370382
| projectA/src/index.js:6:38:6:53 | req.query.taintA | projectA/views/main.ejs:5:5:5:23 | taintedInMiddleware |
371383
| projectA/src/index.js:6:38:6:53 | req.query.taintA | projectA/views/main.ejs:5:5:5:23 | taintedInMiddleware |
372384
| projectA/src/index.js:6:38:6:53 | req.query.taintA | projectA/views/main.ejs:5:5:5:23 | taintedInMiddleware |
@@ -463,6 +475,10 @@ edges
463475
| views/angularjs_sinks.ejs:4:13:4:19 | rawHtml | views/angularjs_sinks.ejs:4:9:4:22 | <%- rawHtml %> |
464476
| views/angularjs_sinks.ejs:4:13:4:19 | rawHtml | views/angularjs_sinks.ejs:4:9:4:22 | <%- rawHtml %> |
465477
| views/angularjs_sinks.ejs:4:13:4:19 | rawHtml | views/angularjs_sinks.ejs:4:9:4:22 | <%- rawHtml %> |
478+
| views/dot_sinks.html.dot:3:13:3:19 | tainted | views/dot_sinks.html.dot:3:9:3:22 | {{! tainted }} |
479+
| views/dot_sinks.html.dot:3:13:3:19 | tainted | views/dot_sinks.html.dot:3:9:3:22 | {{! tainted }} |
480+
| views/dot_sinks.html.dot:3:13:3:19 | tainted | views/dot_sinks.html.dot:3:9:3:22 | {{! tainted }} |
481+
| views/dot_sinks.html.dot:3:13:3:19 | tainted | views/dot_sinks.html.dot:3:9:3:22 | {{! tainted }} |
466482
| views/ejs_include1.ejs:1:5:1:7 | foo | views/ejs_include1.ejs:1:1:1:10 | <%- foo %> |
467483
| views/ejs_include1.ejs:1:5:1:7 | foo | views/ejs_include1.ejs:1:1:1:10 | <%- foo %> |
468484
| views/ejs_include1.ejs:1:5:1:7 | foo | views/ejs_include1.ejs:1:1:1:10 | <%- foo %> |
@@ -553,6 +569,7 @@ edges
553569
| projectB/views/subfolder/other.ejs:3:1:3:12 | <%- sinkB %> | projectB/src/index.js:43:16:43:30 | req.query.sinkB | projectB/views/subfolder/other.ejs:3:1:3:12 | <%- sinkB %> | Cross-site scripting vulnerability due to $@. | projectB/src/index.js:43:16:43:30 | req.query.sinkB | user-provided value |
554570
| views/angularjs_include.ejs:3:5:3:18 | <%- rawHtml %> | app.js:66:18:66:34 | req.query.rawHtml | views/angularjs_include.ejs:3:5:3:18 | <%- rawHtml %> | Cross-site scripting vulnerability due to $@. | app.js:66:18:66:34 | req.query.rawHtml | user-provided value |
555571
| views/angularjs_sinks.ejs:4:9:4:22 | <%- rawHtml %> | app.js:66:18:66:34 | req.query.rawHtml | views/angularjs_sinks.ejs:4:9:4:22 | <%- rawHtml %> | Cross-site scripting vulnerability due to $@. | app.js:66:18:66:34 | req.query.rawHtml | user-provided value |
572+
| views/dot_sinks.html.dot:3:9:3:22 | {{! tainted }} | app.js:73:18:73:30 | req.query.foo | views/dot_sinks.html.dot:3:9:3:22 | {{! tainted }} | Cross-site scripting vulnerability due to $@. | app.js:73:18:73:30 | req.query.foo | user-provided value |
556573
| views/ejs_include1.ejs:1:1:1:10 | <%- foo %> | app.js:8:18:8:34 | req.query.rawHtml | views/ejs_include1.ejs:1:1:1:10 | <%- foo %> | Cross-site scripting vulnerability due to $@. | app.js:8:18:8:34 | req.query.rawHtml | user-provided value |
557574
| views/ejs_include2.ejs:1:1:1:14 | <%- rawHtml %> | app.js:8:18:8:34 | req.query.rawHtml | views/ejs_include2.ejs:1:1:1:14 | <%- rawHtml %> | Cross-site scripting vulnerability due to $@. | app.js:8:18:8:34 | req.query.rawHtml | user-provided value |
558575
| views/ejs_sinks.ejs:4:9:4:22 | <%- rawHtml %> | app.js:8:18:8:34 | req.query.rawHtml | views/ejs_sinks.ejs:4:9:4:22 | <%- rawHtml %> | Cross-site scripting vulnerability due to $@. | app.js:8:18:8:34 | req.query.rawHtml | user-provided value |

javascript/ql/test/library-tests/frameworks/Templating/app.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,16 @@ app.get('/angularjs', (req, res) => {
6666
rawHtml: req.query.rawHtml,
6767
});
6868
});
69+
70+
app.get('/dotjs', (req, res) => {
71+
// Currently we don't auto-insert the full .html.dot extension. Test all variations.
72+
res.render('dot_sinks.html.dot', {
73+
tainted: req.query.foo,
74+
});
75+
res.render('dot_sinks.html', {
76+
tainted: req.query.foo,
77+
});
78+
res.render('dot_sinks', {
79+
tainted: req.query.foo,
80+
});
81+
});

javascript/ql/test/library-tests/frameworks/Templating/test.expected

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ getLikelyTemplateSyntax
1212
| projectB/views/subfolder/other.ejs:0:0:0:0 | projectB/views/subfolder/other.ejs | ejs |
1313
| views/angularjs_include.ejs:0:0:0:0 | views/angularjs_include.ejs | ejs |
1414
| views/angularjs_sinks.ejs:0:0:0:0 | views/angularjs_sinks.ejs | ejs |
15+
| views/dot_sinks.html.dot:0:0:0:0 | views/dot_sinks.html.dot | dot |
1516
| views/ejs_include1.ejs:0:0:0:0 | views/ejs_include1.ejs | ejs |
1617
| views/ejs_include2.ejs:0:0:0:0 | views/ejs_include2.ejs | ejs |
1718
| views/ejs_sinks.ejs:0:0:0:0 | views/ejs_sinks.ejs | ejs |
@@ -24,6 +25,7 @@ getTargetFile
2425
| app.js:25:5:40:6 | res.ren ... \\n }) | views/hbs_sinks.hbs:0:0:0:0 | views/hbs_sinks.hbs |
2526
| app.js:44:5:60:6 | res.ren ... \\n }) | views/njk_sinks.njk:0:0:0:0 | views/njk_sinks.njk |
2627
| app.js:64:5:67:6 | res.ren ... \\n }) | views/angularjs_sinks.ejs:0:0:0:0 | views/angularjs_sinks.ejs |
28+
| app.js:72:5:74:6 | res.ren ... \\n }) | views/dot_sinks.html.dot:0:0:0:0 | views/dot_sinks.html.dot |
2729
| consolidate.js:3:1:3:83 | consoli ... => {}) | views/instantiated_as_ejs.html:0:0:0:0 | views/instantiated_as_ejs.html |
2830
| consolidate.js:4:1:4:90 | consoli ... => {}) | views/instantiated_as_hbs.html:0:0:0:0 | views/instantiated_as_hbs.html |
2931
| projectA/src/index.js:11:5:14:6 | res.ren ... \\n }) | projectA/views/main.ejs:0:0:0:0 | projectA/views/main.ejs |
@@ -50,6 +52,7 @@ xssSink
5052
| projectB/views/subfolder/other.ejs:3:1:3:12 | <%- sinkB %> |
5153
| views/angularjs_include.ejs:3:5:3:18 | <%- rawHtml %> |
5254
| views/angularjs_sinks.ejs:4:9:4:22 | <%- rawHtml %> |
55+
| views/dot_sinks.html.dot:3:9:3:22 | {{! tainted }} |
5356
| views/ejs_include1.ejs:1:1:1:10 | <%- foo %> |
5457
| views/ejs_include2.ejs:1:1:1:14 | <%- rawHtml %> |
5558
| views/ejs_sinks.ejs:4:9:4:22 | <%- rawHtml %> |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<html>
2+
<body>
3+
{{! tainted }}
4+
{{= tainted }}
5+
</body>
6+
</html>

0 commit comments

Comments
 (0)