Skip to content

Commit 57bf92a

Browse files
authored
Merge pull request #10347 from erik-krogh/mermaid
JS: add a markdown step through the `mermaid` library
2 parents 1d83479 + 0407198 commit 57bf92a

File tree

4 files changed

+101
-1
lines changed

4 files changed

+101
-1
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* A model for the `mermaid` library has been added. XSS queries can now detect flow through the `render` method of the `mermaid` library.

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,32 @@ module Markdown {
7878
}
7979
}
8080

81+
/** A taint step for the `mermaid` library. */
82+
private class MermaidStep extends MarkdownStep {
83+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
84+
exists(API::CallNode call |
85+
call =
86+
[API::moduleImport("mermaid"), API::moduleImport("mermaid").getMember("mermaidAPI")]
87+
.getMember("render")
88+
.getACall()
89+
|
90+
succ = [call, call.getParameter(2).getParameter(0).asSource()] and
91+
pred = call.getArgument(1)
92+
)
93+
or
94+
exists(DataFlow::CallNode call |
95+
call =
96+
[
97+
DataFlow::globalVarRef("mermaid"),
98+
DataFlow::globalVarRef("mermaid").getAPropertyRead("mermaidAPI")
99+
].getAMemberCall("render")
100+
|
101+
succ = [call.(DataFlow::Node), call.getABoundCallbackParameter(2, 0)] and
102+
pred = call.getArgument(1)
103+
)
104+
}
105+
}
106+
81107
/**
82108
* Classes and predicates for modeling taint steps in `unified` and `remark`.
83109
*/

javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/UnsafeHtmlConstruction.expected

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,22 @@ nodes
5656
| main.js:93:43:93:43 | x |
5757
| main.js:93:43:93:43 | x |
5858
| main.js:94:31:94:31 | x |
59+
| main.js:98:43:98:43 | x |
60+
| main.js:98:43:98:43 | x |
61+
| main.js:99:28:99:28 | x |
62+
| main.js:99:28:99:28 | x |
63+
| main.js:103:43:103:43 | x |
64+
| main.js:103:43:103:43 | x |
65+
| main.js:105:26:105:26 | x |
66+
| main.js:105:26:105:26 | x |
67+
| main.js:109:41:109:41 | x |
68+
| main.js:109:41:109:41 | x |
69+
| main.js:111:37:111:37 | x |
70+
| main.js:111:37:111:37 | x |
71+
| main.js:116:47:116:47 | s |
72+
| main.js:116:47:116:47 | s |
73+
| main.js:117:34:117:34 | s |
74+
| main.js:117:34:117:34 | s |
5975
| typed.ts:1:39:1:39 | s |
6076
| typed.ts:1:39:1:39 | s |
6177
| typed.ts:2:29:2:29 | s |
@@ -126,6 +142,30 @@ edges
126142
| main.js:93:43:93:43 | x | main.js:94:31:94:31 | x |
127143
| main.js:93:43:93:43 | x | main.js:94:31:94:31 | x |
128144
| main.js:94:31:94:31 | x | main.js:89:21:89:21 | x |
145+
| main.js:98:43:98:43 | x | main.js:99:28:99:28 | x |
146+
| main.js:98:43:98:43 | x | main.js:99:28:99:28 | x |
147+
| main.js:98:43:98:43 | x | main.js:99:28:99:28 | x |
148+
| main.js:98:43:98:43 | x | main.js:99:28:99:28 | x |
149+
| main.js:98:43:98:43 | x | main.js:103:43:103:43 | x |
150+
| main.js:98:43:98:43 | x | main.js:103:43:103:43 | x |
151+
| main.js:98:43:98:43 | x | main.js:103:43:103:43 | x |
152+
| main.js:98:43:98:43 | x | main.js:103:43:103:43 | x |
153+
| main.js:98:43:98:43 | x | main.js:105:26:105:26 | x |
154+
| main.js:98:43:98:43 | x | main.js:105:26:105:26 | x |
155+
| main.js:98:43:98:43 | x | main.js:105:26:105:26 | x |
156+
| main.js:98:43:98:43 | x | main.js:105:26:105:26 | x |
157+
| main.js:98:43:98:43 | x | main.js:109:41:109:41 | x |
158+
| main.js:98:43:98:43 | x | main.js:109:41:109:41 | x |
159+
| main.js:98:43:98:43 | x | main.js:109:41:109:41 | x |
160+
| main.js:98:43:98:43 | x | main.js:109:41:109:41 | x |
161+
| main.js:98:43:98:43 | x | main.js:111:37:111:37 | x |
162+
| main.js:98:43:98:43 | x | main.js:111:37:111:37 | x |
163+
| main.js:98:43:98:43 | x | main.js:111:37:111:37 | x |
164+
| main.js:98:43:98:43 | x | main.js:111:37:111:37 | x |
165+
| main.js:116:47:116:47 | s | main.js:117:34:117:34 | s |
166+
| main.js:116:47:116:47 | s | main.js:117:34:117:34 | s |
167+
| main.js:116:47:116:47 | s | main.js:117:34:117:34 | s |
168+
| main.js:116:47:116:47 | s | main.js:117:34:117:34 | s |
129169
| typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s |
130170
| typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s |
131171
| typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s |
@@ -153,5 +193,11 @@ edges
153193
| main.js:67:63:67:69 | attrVal | main.js:66:35:66:41 | attrVal | main.js:67:63:67:69 | attrVal | $@ based on $@ might later cause $@. | main.js:67:63:67:69 | attrVal | HTML construction | main.js:66:35:66:41 | attrVal | library input | main.js:67:47:67:78 | "<img a ... "\\"/>" | cross-site scripting |
154194
| main.js:81:35:81:37 | val | main.js:79:34:79:36 | val | main.js:81:35:81:37 | val | $@ based on $@ might later cause $@. | main.js:81:35:81:37 | val | HTML construction | main.js:79:34:79:36 | val | library input | main.js:81:24:81:49 | "<span> ... /span>" | cross-site scripting |
155195
| main.js:90:23:90:23 | x | main.js:93:43:93:43 | x | main.js:90:23:90:23 | x | $@ based on $@ might later cause $@. | main.js:90:23:90:23 | x | HTML construction | main.js:93:43:93:43 | x | library input | main.js:94:20:94:32 | createHTML(x) | cross-site scripting |
196+
| main.js:99:28:99:28 | x | main.js:98:43:98:43 | x | main.js:99:28:99:28 | x | $@ based on $@ might later cause $@. | main.js:99:28:99:28 | x | Markdown rendering | main.js:98:43:98:43 | x | library input | main.js:100:24:100:26 | svg | cross-site scripting |
197+
| main.js:103:43:103:43 | x | main.js:98:43:98:43 | x | main.js:103:43:103:43 | x | $@ based on $@ might later cause $@. | main.js:103:43:103:43 | x | Markdown rendering | main.js:98:43:98:43 | x | library input | main.js:103:20:103:44 | myMerma ... id", x) | cross-site scripting |
198+
| main.js:105:26:105:26 | x | main.js:98:43:98:43 | x | main.js:105:26:105:26 | x | $@ based on $@ might later cause $@. | main.js:105:26:105:26 | x | Markdown rendering | main.js:98:43:98:43 | x | library input | main.js:106:24:106:26 | svg | cross-site scripting |
199+
| main.js:109:41:109:41 | x | main.js:98:43:98:43 | x | main.js:109:41:109:41 | x | $@ based on $@ might later cause $@. | main.js:109:41:109:41 | x | Markdown rendering | main.js:98:43:98:43 | x | library input | main.js:109:20:109:42 | mermaid ... id", x) | cross-site scripting |
200+
| main.js:111:37:111:37 | x | main.js:98:43:98:43 | x | main.js:111:37:111:37 | x | $@ based on $@ might later cause $@. | main.js:111:37:111:37 | x | Markdown rendering | main.js:98:43:98:43 | x | library input | main.js:112:24:112:26 | svg | cross-site scripting |
201+
| main.js:117:34:117:34 | s | main.js:116:47:116:47 | s | main.js:117:34:117:34 | s | $@ based on $@ might later cause $@. | main.js:117:34:117:34 | s | Markdown rendering | main.js:116:47:116:47 | s | library input | main.js:118:53:118:56 | html | cross-site scripting |
156202
| typed.ts:2:29:2:29 | s | typed.ts:1:39:1:39 | s | typed.ts:2:29:2:29 | s | $@ based on $@ might later cause $@. | typed.ts:2:29:2:29 | s | HTML construction | typed.ts:1:39:1:39 | s | library input | typed.ts:3:31:3:34 | html | cross-site scripting |
157203
| typed.ts:8:40:8:40 | s | typed.ts:6:43:6:43 | s | typed.ts:8:40:8:40 | s | $@ based on $@ might later cause $@. | typed.ts:8:40:8:40 | s | HTML construction | typed.ts:6:43:6:43 | s | library input | typed.ts:8:29:8:52 | "<span> ... /span>" | cross-site scripting |

javascript/ql/test/query-tests/Security/CWE-079/UnsafeHtmlConstruction/main.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,28 @@ function createHTML(x) {
9292

9393
module.exports.usesCreateHTML = function (x) {
9494
$("#foo").html(createHTML(x));
95-
}
95+
}
96+
97+
const myMermaid = require('mermaid');
98+
module.exports.usesCreateHTML = function (x) {
99+
myMermaid.render("id", x, function (svg) { // NOT OK
100+
$("#foo").html(svg);
101+
});
102+
103+
$("#foo").html(myMermaid.render("id", x)); // NOT OK
104+
105+
mermaid.render("id", x, function (svg) {// NOT OK
106+
$("#foo").html(svg);
107+
});
108+
109+
$("#foo").html(mermaid.render("id", x)); // NOT OK
110+
111+
mermaid.mermaidAPI.render("id", x, function (svg) {// NOT OK
112+
$("#foo").html(svg);
113+
});
114+
}
115+
116+
module.exports.xssThroughMarkdown = function (s) {
117+
const html = markdown.render(s); // NOT OK
118+
document.querySelector("#markdown").innerHTML = html;
119+
}

0 commit comments

Comments
 (0)