Skip to content

Commit fd429ce

Browse files
author
Esben Sparre Andreasen
committed
JS: whitelist delimiter unwrapping for js/incomplete-sanitization
1 parent a0ed362 commit fd429ce

File tree

2 files changed

+32
-7
lines changed

2 files changed

+32
-7
lines changed

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,34 @@ predicate allBackslashesEscaped(DataFlow::Node nd) {
101101
allBackslashesEscaped(nd.getAPredecessor())
102102
}
103103

104+
/**
105+
* Holds if `repl` looks like a call to "String.prototype.replace" that deliberately removes the first occurrence of `str`.
106+
*/
107+
predicate removesFirstOccurence(DataFlow::MethodCallNode repl, string str) {
108+
repl.getMethodName() = "replace" and
109+
repl.getArgument(0).getStringValue() = str and
110+
repl.getArgument(1).getStringValue() = ""
111+
}
112+
113+
/**
114+
* Holds if `leftUnwrap` and `rightUnwrap` unwraps a string from a pair of surrounding delimiters.
115+
*/
116+
predicate isDelimiterUnwrapper(
117+
DataFlow::MethodCallNode leftUnwrap, DataFlow::MethodCallNode rightUnwrap
118+
) {
119+
exists(string left, string right |
120+
left = "[" and right = "]"
121+
or
122+
left = "{" and right = "}"
123+
or
124+
left = "(" and right = ")"
125+
|
126+
removesFirstOccurence(leftUnwrap, left) and
127+
removesFirstOccurence(rightUnwrap, right) and
128+
leftUnwrap.getAMethodCall() = rightUnwrap
129+
)
130+
}
131+
104132
from MethodCallExpr repl, Expr old, string msg
105133
where
106134
repl.getMethodName() = "replace" and
@@ -122,7 +150,10 @@ where
122150
)
123151
) and
124152
// don't flag replace operations in a loop
125-
not DataFlow::valueNode(repl.getReceiver()) = DataFlow::valueNode(repl).getASuccessor+()
153+
not DataFlow::valueNode(repl.getReceiver()) = DataFlow::valueNode(repl).getASuccessor+() and
154+
// dont' flag unwrapper
155+
not isDelimiterUnwrapper(repl.flow(), _) and
156+
not isDelimiterUnwrapper(_, repl.flow())
126157
or
127158
exists(RegExpLiteral rel |
128159
isBackslashEscape(repl, rel) and

javascript/ql/test/query-tests/Security/CWE-116/IncompleteSanitization/IncompleteSanitization.expected

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,12 @@
1515
| tst.js:61:10:61:18 | s.replace | This replaces only the first occurrence of "'" + "". |
1616
| tst.js:65:10:65:18 | s.replace | This replaces only the first occurrence of "'". |
1717
| tst.js:69:10:69:18 | s.replace | This replaces only the first occurrence of "'" + "". |
18-
| tst.js:130:2:130:10 | s.replace | This replaces only the first occurrence of '['. |
19-
| tst.js:130:2:130:27 | s.repla ... replace | This replaces only the first occurrence of ']'. |
20-
| tst.js:132:2:132:10 | s.replace | This replaces only the first occurrence of '{'. |
21-
| tst.js:132:2:132:27 | s.repla ... replace | This replaces only the first occurrence of '}'. |
2218
| tst.js:133:2:133:10 | s.replace | This replaces only the first occurrence of '<'. |
2319
| tst.js:133:2:133:27 | s.repla ... replace | This replaces only the first occurrence of '>'. |
2420
| tst.js:135:2:135:10 | s.replace | This replaces only the first occurrence of '['. |
2521
| tst.js:135:2:135:30 | s.repla ... replace | This replaces only the first occurrence of ']'. |
2622
| tst.js:136:2:136:10 | s.replace | This replaces only the first occurrence of '{'. |
2723
| tst.js:136:2:136:30 | s.repla ... replace | This replaces only the first occurrence of '}'. |
28-
| tst.js:138:6:138:14 | s.replace | This replaces only the first occurrence of '['. |
29-
| tst.js:139:6:139:14 | s.replace | This replaces only the first occurrence of ']'. |
3024
| tst.js:140:2:140:10 | s.replace | This replaces only the first occurrence of /{/. |
3125
| tst.js:140:2:140:27 | s.repla ... replace | This replaces only the first occurrence of /}/. |
3226
| tst.js:141:2:141:10 | s.replace | This replaces only the first occurrence of ']'. |

0 commit comments

Comments
 (0)