Skip to content

Commit d71adff

Browse files
committed
dont sanitize global replacements where the regexp is a char class
1 parent 0a17b04 commit d71adff

4 files changed

Lines changed: 30 additions & 1 deletion

File tree

javascript/ql/src/semmle/javascript/security/performance/PolynomialReDoSCustomizations.qll

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,13 @@ module PolynomialReDoS {
8484
*/
8585
class StringLengthLimiter extends Sanitizer {
8686
StringLengthLimiter() {
87-
this.(StringReplaceCall).isGlobal()
87+
this.(StringReplaceCall).isGlobal() and
88+
// not char classes - they don't remove any repeated pattern.
89+
not exists(RegExpTerm root | root = this.(StringReplaceCall).getRegExp().getRoot() |
90+
root instanceof RegExpCharacterClass
91+
or
92+
root instanceof RegExpCharacterClassEscape
93+
)
8894
or
8995
exists(string name | name = "slice" or name = "substring" or name = "substr" |
9096
this.(DataFlow::MethodCallNode).getMethodName() = name

javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
| polynomial-redos.js:114:22:114:24 | \\w* | Strings starting with '5' and with many repetitions of '5' can start matching anywhere after the start of the preceeding \\d* |
105105
| polynomial-redos.js:116:21:116:28 | [\\d\\D]*? | Strings starting with '/*' and with many repetitions of 'a/*' can start matching anywhere after the start of the preceeding \\/\\*[\\d\\D]*?\\*\\/ |
106106
| polynomial-redos.js:118:17:118:23 | (#\\d+)+ | Strings with many repetitions of '9' can start matching anywhere after the start of the preceeding \\d+ |
107+
| polynomial-redos.js:124:33:124:35 | \\s+ | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding \\s+$ |
107108
| regexplib/address.js:27:3:27:5 | \\s* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{4}\\)?(\\s*\|-)\\d{3}(\\s*\|-)\\d{3}\\s*) |
108109
| regexplib/address.js:27:48:27:50 | \\s* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding (\\s*\\(?0\\d{3}\\)?(\\s*\|-)\\d{3}(\\s*\|-)\\d{4}\\s*) |
109110
| regexplib/address.js:27:93:27:95 | \\s* | Strings with many repetitions of ' ' can start matching anywhere after the start of the preceeding (\\s*(7\|8)(\\d{7}\|\\d{3}(\\-\|\\s{1})\\d{4})\\s*) |

javascript/ql/test/query-tests/Performance/ReDoS/PolynomialReDoS.expected

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ nodes
138138
| polynomial-redos.js:116:2:116:8 | tainted |
139139
| polynomial-redos.js:118:2:118:8 | tainted |
140140
| polynomial-redos.js:118:2:118:8 | tainted |
141+
| polynomial-redos.js:121:7:121:55 | replaced |
142+
| polynomial-redos.js:121:18:121:24 | tainted |
143+
| polynomial-redos.js:121:18:121:55 | tainted ... /g, '') |
144+
| polynomial-redos.js:123:3:123:20 | result |
145+
| polynomial-redos.js:123:13:123:20 | replaced |
146+
| polynomial-redos.js:124:12:124:17 | result |
147+
| polynomial-redos.js:124:12:124:17 | result |
141148
edges
142149
| lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name |
143150
| lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name |
@@ -269,10 +276,17 @@ edges
269276
| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:116:2:116:8 | tainted |
270277
| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:118:2:118:8 | tainted |
271278
| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:118:2:118:8 | tainted |
279+
| polynomial-redos.js:5:6:5:32 | tainted | polynomial-redos.js:121:18:121:24 | tainted |
272280
| polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:5:6:5:32 | tainted |
273281
| polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:5:6:5:32 | tainted |
274282
| polynomial-redos.js:68:18:68:24 | req.url | polynomial-redos.js:68:18:68:24 | req.url |
275283
| polynomial-redos.js:69:18:69:25 | req.body | polynomial-redos.js:69:18:69:25 | req.body |
284+
| polynomial-redos.js:121:7:121:55 | replaced | polynomial-redos.js:123:13:123:20 | replaced |
285+
| polynomial-redos.js:121:18:121:24 | tainted | polynomial-redos.js:121:18:121:55 | tainted ... /g, '') |
286+
| polynomial-redos.js:121:18:121:55 | tainted ... /g, '') | polynomial-redos.js:121:7:121:55 | replaced |
287+
| polynomial-redos.js:123:3:123:20 | result | polynomial-redos.js:124:12:124:17 | result |
288+
| polynomial-redos.js:123:3:123:20 | result | polynomial-redos.js:124:12:124:17 | result |
289+
| polynomial-redos.js:123:13:123:20 | replaced | polynomial-redos.js:123:3:123:20 | result |
276290
#select
277291
| lib/lib.js:4:14:4:17 | name | lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name | This expensive $@ use depends on $@. | lib/lib.js:1:15:1:16 | a* | regular expression | lib/lib.js:3:28:3:31 | name | library input |
278292
| polynomial-redos.js:7:2:7:8 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:7:2:7:8 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:7:24:7:26 | \\s+ | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
@@ -349,3 +363,4 @@ edges
349363
| polynomial-redos.js:114:2:114:8 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:114:2:114:8 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:114:22:114:24 | \\w* | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
350364
| polynomial-redos.js:116:2:116:8 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:116:2:116:8 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:116:21:116:28 | [\\d\\D]*? | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
351365
| polynomial-redos.js:118:2:118:8 | tainted | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:118:2:118:8 | tainted | This expensive $@ use depends on $@. | polynomial-redos.js:118:17:118:23 | (#\\d+)+ | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |
366+
| polynomial-redos.js:124:12:124:17 | result | polynomial-redos.js:5:16:5:32 | req.query.tainted | polynomial-redos.js:124:12:124:17 | result | This expensive $@ use depends on $@. | polynomial-redos.js:124:33:124:35 | \\s+ | regular expression | polynomial-redos.js:5:16:5:32 | req.query.tainted | a user-provided value |

javascript/ql/test/query-tests/Performance/ReDoS/polynomial-redos.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,11 @@ app.use(function(req, res) {
116116
tainted.match(/\/\*[\d\D]*?\*\//g); // NOT OK
117117

118118
tainted.match(/(#\d+)+/); // OK - but still flagged due to insufficient suffix-checking.
119+
120+
(function foo() {
121+
var replaced = tainted.replace(/[^\w\s\-\.\_~]/g, '');
122+
var result = ""
123+
result += replaced;
124+
result = result.replace(/^\s+|\s+$/g, ''); // NOT OK
125+
})();
119126
});

0 commit comments

Comments
 (0)