Skip to content

Commit a400a1e

Browse files
committed
split the markdown steps into a separate class
1 parent 059a5f3 commit a400a1e

File tree

1 file changed

+134
-113
lines changed

1 file changed

+134
-113
lines changed

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

Lines changed: 134 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -2,159 +2,180 @@
22
* Provides classes for modelling common markdown parsers and generators.
33
*/
44

5+
import semmle.javascript.Unit
56
import javascript
67

78
/**
8-
* A taint step for the `marked` library, that converts markdown to HTML.
9+
* A module providing taint-steps for common markdown parsers and generators.
910
*/
10-
private class MarkedStep extends TaintTracking::SharedTaintStep {
11-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
12-
exists(DataFlow::CallNode call |
13-
call = DataFlow::globalVarRef("marked").getACall()
14-
or
15-
call = DataFlow::moduleImport("marked").getACall()
16-
|
17-
succ = call and
18-
pred = call.getArgument(0)
19-
)
11+
module Markdown {
12+
/**
13+
* A taint-step that parses a markdown document, but preserves taint.import
14+
*/
15+
class MarkdownStep extends Unit {
16+
abstract predicate step(DataFlow::Node pred, DataFlow::Node succ);
2017
}
21-
}
2218

23-
/**
24-
* A taint step for the `markdown-table` library.
25-
*/
26-
private class MarkdownTableStep extends TaintTracking::SharedTaintStep {
27-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
28-
exists(DataFlow::CallNode call | call = DataFlow::moduleImport("markdown-table").getACall() |
29-
succ = call and
30-
pred = call.getArgument(0)
31-
)
19+
private class MarkdownStepAsTaintStep extends TaintTracking::SharedTaintStep {
20+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
21+
any(MarkdownStep step).step(pred, succ)
22+
}
3223
}
33-
}
3424

35-
/**
36-
* A taint step for the `showdown` library.
37-
*/
38-
private class ShowDownStep extends TaintTracking::SharedTaintStep {
39-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
40-
exists(DataFlow::CallNode call |
41-
call =
42-
[DataFlow::globalVarRef("showdown"), DataFlow::moduleImport("showdown")]
43-
.getAConstructorInvocation("Converter")
44-
.getAMemberCall(["makeHtml", "makeMd"])
45-
|
46-
succ = call and
47-
pred = call.getArgument(0)
48-
)
25+
/**
26+
* A taint step for the `marked` library, that converts markdown to HTML.
27+
*/
28+
private class MarkedStep extends MarkdownStep {
29+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
30+
exists(DataFlow::CallNode call |
31+
call = DataFlow::globalVarRef("marked").getACall()
32+
or
33+
call = DataFlow::moduleImport("marked").getACall()
34+
|
35+
succ = call and
36+
pred = call.getArgument(0)
37+
)
38+
}
4939
}
50-
}
5140

52-
/**
53-
* Classes and predicates for modelling taint steps in `unified` and `remark`.
54-
*/
55-
private module Unified {
5641
/**
57-
* The creation of a parser from `unified`.
58-
* The `remark` module is a shorthand that initializes `unified` with a markdown parser.
42+
* A taint step for the `markdown-table` library.
5943
*/
60-
DataFlow::CallNode unified() { result = DataFlow::moduleImport(["unified", "remark"]).getACall() }
44+
private class MarkdownTableStep extends MarkdownStep {
45+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
46+
exists(DataFlow::CallNode call | call = DataFlow::moduleImport("markdown-table").getACall() |
47+
succ = call and
48+
pred = call.getArgument(0)
49+
)
50+
}
51+
}
6152

6253
/**
63-
* A chain of method calls that process an input with `unified`.
54+
* A taint step for the `showdown` library.
6455
*/
65-
class UnifiedChain extends DataFlow::CallNode {
66-
DataFlow::CallNode root;
67-
68-
UnifiedChain() {
69-
root = unified() and
70-
this = root.getAChainedMethodCall(["process", "processSync"])
56+
private class ShowDownStep extends MarkdownStep {
57+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
58+
exists(DataFlow::CallNode call |
59+
call =
60+
[DataFlow::globalVarRef("showdown"), DataFlow::moduleImport("showdown")]
61+
.getAConstructorInvocation("Converter")
62+
.getAMemberCall(["makeHtml", "makeMd"])
63+
|
64+
succ = call and
65+
pred = call.getArgument(0)
66+
)
7167
}
68+
}
7269

70+
/**
71+
* Classes and predicates for modelling taint steps in `unified` and `remark`.
72+
*/
73+
private module Unified {
7374
/**
74-
* Gets a plugin that is used in this chain.
75+
* The creation of a parser from `unified`.
76+
* The `remark` module is a shorthand that initializes `unified` with a markdown parser.
7577
*/
76-
DataFlow::Node getAUsedPlugin() { result = root.getAChainedMethodCall("use").getArgument(0) }
78+
DataFlow::CallNode unified() {
79+
result = DataFlow::moduleImport(["unified", "remark"]).getACall()
80+
}
7781

7882
/**
79-
* Gets the input that is processed.
83+
* A chain of method calls that process an input with `unified`.
8084
*/
81-
DataFlow::Node getInput() { result = getArgument(0) }
85+
class UnifiedChain extends DataFlow::CallNode {
86+
DataFlow::CallNode root;
87+
88+
UnifiedChain() {
89+
root = unified() and
90+
this = root.getAChainedMethodCall(["process", "processSync"])
91+
}
92+
93+
/**
94+
* Gets a plugin that is used in this chain.
95+
*/
96+
DataFlow::Node getAUsedPlugin() { result = root.getAChainedMethodCall("use").getArgument(0) }
97+
98+
/**
99+
* Gets the input that is processed.
100+
*/
101+
DataFlow::Node getInput() { result = getArgument(0) }
102+
103+
/**
104+
* Gets the processed output.
105+
*/
106+
DataFlow::Node getOutput() {
107+
this.getCalleeName() = "process" and result = getABoundCallbackParameter(1, 1)
108+
or
109+
this.getCalleeName() = "processSync" and result = this
110+
}
111+
}
82112

83113
/**
84-
* Gets the processed output.
114+
* A taint step for the `unified` library.
85115
*/
86-
DataFlow::Node getOutput() {
87-
this.getCalleeName() = "process" and result = getABoundCallbackParameter(1, 1)
88-
or
89-
this.getCalleeName() = "processSync" and result = this
116+
class UnifiedStep extends MarkdownStep {
117+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
118+
exists(UnifiedChain chain |
119+
// sanitizer. Mostly looking for `rehype-sanitize`, but also other plugins with `sanitize` in their name.
120+
not chain.getAUsedPlugin().getALocalSource() =
121+
DataFlow::moduleImport(any(string s | s.matches("%sanitize%")))
122+
|
123+
pred = chain.getInput() and
124+
succ = chain.getOutput()
125+
)
126+
}
90127
}
91128
}
92129

93130
/**
94-
* A taint step for the `unified` library.
131+
* A taint step for the `snarkdown` library.
95132
*/
96-
class UnifiedStep extends TaintTracking::SharedTaintStep {
133+
private class SnarkdownStep extends MarkdownStep {
97134
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
98-
exists(UnifiedChain chain |
99-
// sanitizer. Mostly looking for `rehype-sanitize`, but also other plugins with `sanitize` in their name.
100-
not chain.getAUsedPlugin().getALocalSource() =
101-
DataFlow::moduleImport(any(string s | s.matches("%sanitize%")))
102-
|
103-
pred = chain.getInput() and
104-
succ = chain.getOutput()
135+
exists(DataFlow::CallNode call | call = DataFlow::moduleImport("snarkdown").getACall() |
136+
call = succ and
137+
pred = call.getArgument(0)
105138
)
106139
}
107140
}
108-
}
109141

110-
/**
111-
* A taint step for the `snarkdown` library.
112-
*/
113-
private class SnarkdownStep extends TaintTracking::SharedTaintStep {
114-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
115-
exists(DataFlow::CallNode call | call = DataFlow::moduleImport("snarkdown").getACall() |
116-
call = succ and
117-
pred = call.getArgument(0)
118-
)
119-
}
120-
}
121-
122-
/**
123-
* Classes and predicates for modelling taint steps the `markdown-it` library.
124-
*/
125-
private module MarkdownIt {
126142
/**
127-
* The creation of a parser from `markdown-it`.
143+
* Classes and predicates for modelling taint steps the `markdown-it` library.
128144
*/
129-
private API::Node markdownIt() {
130-
exists(API::InvokeNode call |
131-
call = API::moduleImport("markdown-it").getAnInvocation()
145+
private module MarkdownIt {
146+
/**
147+
* The creation of a parser from `markdown-it`.
148+
*/
149+
private API::Node markdownIt() {
150+
exists(API::InvokeNode call |
151+
call = API::moduleImport("markdown-it").getAnInvocation()
152+
or
153+
call = API::moduleImport("markdown-it").getMember("Markdown").getAnInvocation()
154+
|
155+
call.getParameter(0).getMember("html").getARhs().mayHaveBooleanValue(true) and
156+
result = call.getReturn()
157+
)
132158
or
133-
call = API::moduleImport("markdown-it").getMember("Markdown").getAnInvocation()
134-
|
135-
call.getParameter(0).getMember("html").getARhs().mayHaveBooleanValue(true) and
136-
result = call.getReturn()
137-
)
138-
or
139-
exists(API::CallNode call |
140-
call = markdownIt().getMember(["use", "set", "configure", "enable", "disable"]).getACall() and
141-
result = call.getReturn() and
142-
not call.getParameter(0).getAValueReachingRhs() =
143-
DataFlow::moduleImport("markdown-it-sanitizer")
144-
)
145-
}
146-
147-
/**
148-
* A taint step for the `markdown-it` library.
149-
*/
150-
private class MarkdownItStep extends TaintTracking::SharedTaintStep {
151-
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
152159
exists(API::CallNode call |
153-
call = markdownIt().getMember(["render", "renderInline"]).getACall()
154-
|
155-
succ = call and
156-
pred = call.getArgument(0)
160+
call = markdownIt().getMember(["use", "set", "configure", "enable", "disable"]).getACall() and
161+
result = call.getReturn() and
162+
not call.getParameter(0).getAValueReachingRhs() =
163+
DataFlow::moduleImport("markdown-it-sanitizer")
157164
)
158165
}
166+
167+
/**
168+
* A taint step for the `markdown-it` library.
169+
*/
170+
private class MarkdownItStep extends MarkdownStep {
171+
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
172+
exists(API::CallNode call |
173+
call = markdownIt().getMember(["render", "renderInline"]).getACall()
174+
|
175+
succ = call and
176+
pred = call.getArgument(0)
177+
)
178+
}
179+
}
159180
}
160181
}

0 commit comments

Comments
 (0)