Skip to content

Commit d95b295

Browse files
authored
Merge pull request github#5400 from erik-krogh/replaceCallbacks
Approved by asgerf
2 parents 5b2d5ee + dab6a11 commit d95b295

File tree

5 files changed

+53
-1
lines changed

5 files changed

+53
-1
lines changed

javascript/ql/src/semmle/javascript/StandardLibrary.qll

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,25 @@ class StringReplaceCall extends DataFlow::MethodCallNode {
149149
pr.flowsTo(replacer.getAReturn()) and
150150
map.hasPropertyWrite(old, any(DataFlow::Node repl | repl.getStringValue() = new))
151151
)
152+
or
153+
// str.replace(regex, match => {
154+
// if (match === 'old') return 'new';
155+
// if (match === 'foo') return 'bar';
156+
// ...
157+
// })
158+
exists(
159+
DataFlow::FunctionNode replacer, ConditionGuardNode guard, EqualityTest test,
160+
DataFlow::Node ret
161+
|
162+
replacer = getCallback(1) and
163+
guard.getOutcome() = test.getPolarity() and
164+
guard.getTest() = test and
165+
replacer.getParameter(0).flowsToExpr(test.getAnOperand()) and
166+
test.getAnOperand().getStringValue() = old and
167+
ret = replacer.getAReturn() and
168+
guard.dominates(ret.getBasicBlock()) and
169+
new = ret.getStringValue()
170+
)
152171
}
153172
}
154173

javascript/ql/src/semmle/javascript/security/IncompleteBlacklistSanitizer.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ class StringReplaceCallSequence extends DataFlow::CallNode {
5151

5252
/** Gets a string that is the replacement of this call. */
5353
string getAReplacementString() {
54-
// this is more restrictive than `StringReplaceCall::replaces/2`, in the name of precision
54+
getAMember().replaces(_, result)
55+
or
56+
// StringReplaceCall::replaces/2 can't always find the `old` string, so this is added as a fallback.
5557
getAMember().getRawReplacement().getStringValue() = result
5658
}
5759

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,5 @@
6363
| tst.js:303:10:303:34 | s().rep ... /g, '') | This HTML sanitizer does not sanitize single quotes |
6464
| tst.js:304:9:304:33 | s().rep ... ]/g,'') | This HTML sanitizer does not sanitize single quotes |
6565
| tst.js:305:10:305:34 | s().rep ... ]/g,'') | This HTML sanitizer does not sanitize double quotes |
66+
| tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | This HTML sanitizer does not sanitize single quotes |
67+
| tst.js:320:9:329:3 | s().rep ... ;";\\n\\t}) | This HTML sanitizer does not sanitize single quotes |

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ nodes
3838
| tst.js:303:10:303:34 | s().rep ... /g, '') |
3939
| tst.js:303:10:303:34 | s().rep ... /g, '') |
4040
| tst.js:303:10:303:34 | s().rep ... /g, '') |
41+
| tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) |
42+
| tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) |
43+
| tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) |
4144
edges
4245
| tst.js:243:9:243:31 | s().rep ... ]/g,'') | tst.js:243:9:243:31 | s().rep ... ]/g,'') |
4346
| tst.js:244:9:244:33 | s().rep ... /g, '') | tst.js:244:9:244:33 | s().rep ... /g, '') |
@@ -55,6 +58,7 @@ edges
5558
| tst.js:301:10:301:32 | s().rep ... ]/g,'') | tst.js:301:10:301:32 | s().rep ... ]/g,'') |
5659
| tst.js:302:10:302:34 | s().rep ... ]/g,'') | tst.js:302:10:302:34 | s().rep ... ]/g,'') |
5760
| tst.js:303:10:303:34 | s().rep ... /g, '') | tst.js:303:10:303:34 | s().rep ... /g, '') |
61+
| tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) |
5862
#select
5963
| tst.js:243:9:243:31 | s().rep ... ]/g,'') | tst.js:243:9:243:31 | s().rep ... ]/g,'') | tst.js:243:9:243:31 | s().rep ... ]/g,'') | Cross-site scripting vulnerability as the output of $@ may contain double quotes when it reaches this attribute definition. | tst.js:243:9:243:31 | s().rep ... ]/g,'') | this final HTML sanitizer step |
6064
| tst.js:244:9:244:33 | s().rep ... /g, '') | tst.js:244:9:244:33 | s().rep ... /g, '') | tst.js:244:9:244:33 | s().rep ... /g, '') | Cross-site scripting vulnerability as the output of $@ may contain double quotes when it reaches this attribute definition. | tst.js:244:9:244:33 | s().rep ... /g, '') | this final HTML sanitizer step |
@@ -68,3 +72,4 @@ edges
6872
| tst.js:301:10:301:32 | s().rep ... ]/g,'') | tst.js:301:10:301:32 | s().rep ... ]/g,'') | tst.js:301:10:301:32 | s().rep ... ]/g,'') | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:301:10:301:32 | s().rep ... ]/g,'') | this final HTML sanitizer step |
6973
| tst.js:302:10:302:34 | s().rep ... ]/g,'') | tst.js:302:10:302:34 | s().rep ... ]/g,'') | tst.js:302:10:302:34 | s().rep ... ]/g,'') | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:302:10:302:34 | s().rep ... ]/g,'') | this final HTML sanitizer step |
7074
| tst.js:303:10:303:34 | s().rep ... /g, '') | tst.js:303:10:303:34 | s().rep ... /g, '') | tst.js:303:10:303:34 | s().rep ... /g, '') | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:303:10:303:34 | s().rep ... /g, '') | this final HTML sanitizer step |
75+
| tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | Cross-site scripting vulnerability as the output of $@ may contain single quotes when it reaches this attribute definition. | tst.js:309:10:318:3 | s().rep ... ;";\\n\\t}) | this final HTML sanitizer step |

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,3 +304,27 @@ function incompleteHtmlAttributeSanitization2() {
304304
'="' + s().replace(/[<>&"]/g,'') + '"'; // OK
305305
'=\'' + s().replace(/[<>&']/g,'') + '\''; // OK
306306
}
307+
308+
function incompleteComplexSanitizers() {
309+
'=\'' + s().replace(/[&<>"]/gm, function (str) { // NOT OK
310+
if (str === "&")
311+
return "&amp;";
312+
if (str === "<")
313+
return "&lt;";
314+
if (str === ">")
315+
return "&gt;";
316+
if (str === "\"")
317+
return "&quot;";
318+
}) + '\'';
319+
320+
'="' + s().replace(/[&<>"]/gm, function (str) { // OK
321+
if (str === "&")
322+
return "&amp;";
323+
if (str === "<")
324+
return "&lt;";
325+
if (str === ">")
326+
return "&gt;";
327+
if (str === "\"")
328+
return "&quot;";
329+
}) + '"';
330+
}

0 commit comments

Comments
 (0)