Skip to content

Commit 5dcf55e

Browse files
author
Max Schaefer
committed
JavaScript: Refactor DoubleEscaping.ql.
1 parent 62859d1 commit 5dcf55e

1 file changed

Lines changed: 40 additions & 20 deletions

File tree

javascript/ql/src/Security/CWE-116/DoubleEscaping.ql

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -62,30 +62,23 @@ predicate escapingScheme(string metachar, string regex) {
6262
}
6363

6464
/**
65-
* A call to `String.prototype.replace` that replaces all instances of a pattern.
65+
* A method call that performs string replacement.
6666
*/
67-
class Replacement extends DataFlow::Node {
68-
RegExpLiteral pattern;
67+
abstract class Replacement extends DataFlow::Node {
68+
/**
69+
* Holds if this replacement replaces the string `input` with `output`.
70+
*/
71+
abstract predicate replaces(string input, string output);
6972

70-
Replacement() {
71-
exists(DataFlow::MethodCallNode mcn | this = mcn |
72-
mcn.getMethodName() = "replace" and
73-
pattern.flow().(DataFlow::SourceNode).flowsTo(mcn.getArgument(0)) and
74-
mcn.getNumArgument() = 2 and
75-
pattern.isGlobal()
76-
)
77-
}
73+
/**
74+
* Gets the input of this replacement.
75+
*/
76+
abstract DataFlow::Node getInput();
7877

7978
/**
80-
* Holds if this replacement replaces the string `input` with `output`.
79+
* Gets the output of this replacement.
8180
*/
82-
predicate replaces(string input, string output) {
83-
exists(DataFlow::MethodCallNode mcn |
84-
mcn = this and
85-
input = getStringValue(pattern) and
86-
output = mcn.getArgument(1).getStringValue()
87-
)
88-
}
81+
abstract DataFlow::SourceNode getOutput();
8982

9083
/**
9184
* Holds if this replacement escapes `char` using `metachar`.
@@ -119,7 +112,7 @@ class Replacement extends DataFlow::Node {
119112
* Gets the previous replacement in this chain of replacements.
120113
*/
121114
Replacement getPreviousReplacement() {
122-
result = getASimplePredecessor*(this.(DataFlow::MethodCallNode).getReceiver())
115+
result.getOutput() = getASimplePredecessor*(getInput())
123116
}
124117

125118
/**
@@ -147,6 +140,33 @@ class Replacement extends DataFlow::Node {
147140
}
148141
}
149142

143+
/**
144+
* A call to `String.prototype.replace` that replaces all instances of a pattern.
145+
*/
146+
class GlobalStringReplacement extends Replacement, DataFlow::MethodCallNode {
147+
RegExpLiteral pattern;
148+
149+
GlobalStringReplacement() {
150+
this.getMethodName() = "replace" and
151+
pattern.flow().(DataFlow::SourceNode).flowsTo(this.getArgument(0)) and
152+
this.getNumArgument() = 2 and
153+
pattern.isGlobal()
154+
}
155+
156+
override predicate replaces(string input, string output) {
157+
input = getStringValue(pattern) and
158+
output = this.getArgument(1).getStringValue()
159+
}
160+
161+
override DataFlow::Node getInput() {
162+
result = this.getReceiver()
163+
}
164+
165+
override DataFlow::SourceNode getOutput() {
166+
result = this
167+
}
168+
}
169+
150170
from Replacement primary, Replacement supplementary, string message, string metachar
151171
where
152172
primary.escapes(metachar, _) and

0 commit comments

Comments
 (0)