Skip to content

Commit c8c15a0

Browse files
authored
Merge pull request #17910 from Napalys/napalys/matchAll-support
JS: Support for matchAll
2 parents 3fdd35c + 00790bf commit c8c15a0

File tree

16 files changed

+179
-10
lines changed

16 files changed

+179
-10
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
Added support for `String.prototype.matchAll`.

javascript/ql/lib/semmle/javascript/MembershipCandidates.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ module MembershipCandidate {
193193
or
194194
// u.match(/re/) or u.match("re")
195195
base = this and
196-
m = "match" and
196+
m = ["match", "matchAll"] and
197197
enumeration = RegExp::getRegExpFromNode(firstArg)
198198
)
199199
}

javascript/ql/lib/semmle/javascript/Regexp.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ private predicate isMatchObjectProperty(string name) {
938938

939939
/** Holds if `call` is a call to `match` whose result is used in a way that is incompatible with Match objects. */
940940
private predicate isUsedAsNonMatchObject(DataFlow::MethodCallNode call) {
941-
call.getMethodName() = "match" and
941+
call.getMethodName() = ["match", "matchAll"] and
942942
call.getNumArgument() = 1 and
943943
(
944944
// Accessing a property that is absent on Match objects
@@ -996,7 +996,7 @@ predicate isInterpretedAsRegExp(DataFlow::Node source) {
996996
not isNativeStringMethod(func, methodName)
997997
)
998998
|
999-
methodName = "match" and
999+
methodName = ["match", "matchAll"] and
10001000
source = mce.getArgument(0) and
10011001
mce.getNumArgument() = 1 and
10021002
not isUsedAsNonMatchObject(mce)

javascript/ql/lib/semmle/javascript/StringOps.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -722,7 +722,7 @@ module StringOps {
722722
}
723723

724724
private class MatchCall extends DataFlow::MethodCallNode {
725-
MatchCall() { this.getMethodName() = "match" }
725+
MatchCall() { this.getMethodName() = ["match", "matchAll"] }
726726
}
727727

728728
private class ExecCall extends DataFlow::MethodCallNode {

javascript/ql/lib/semmle/javascript/dataflow/TaintTracking.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -716,7 +716,7 @@ module TaintTracking {
716716

717717
pragma[nomagic]
718718
private DataFlow::MethodCallNode matchMethodCall() {
719-
result.getMethodName() = "match" and
719+
result.getMethodName() = ["match", "matchAll"] and
720720
exists(DataFlow::AnalyzedNode analyzed |
721721
pragma[only_bind_into](analyzed) = result.getArgument(0).analyze() and
722722
analyzed.getAType() = TTRegExp()
@@ -904,7 +904,7 @@ module TaintTracking {
904904
*/
905905
private ControlFlowNode getACaptureSetter(DataFlow::Node input) {
906906
exists(DataFlow::MethodCallNode call | result = call.asExpr() |
907-
call.getMethodName() = ["search", "replace", "replaceAll", "match"] and
907+
call.getMethodName() = ["search", "replace", "replaceAll", "match", "matchAll"] and
908908
input = call.getReceiver()
909909
or
910910
call.getMethodName() = ["test", "exec"] and input = call.getArgument(0)
@@ -985,7 +985,7 @@ module TaintTracking {
985985
or
986986
// u.match(/re/) or u.match("re")
987987
base = expr and
988-
m = "match" and
988+
m = ["match", "matchAll"] and
989989
RegExp::isGenericRegExpSanitizer(RegExp::getRegExpFromNode(firstArg.flow()),
990990
sanitizedOutcome)
991991
)

javascript/ql/src/Security/CWE-020/MissingRegExpAnchor.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ private module Impl implements
3535
|
3636
name = "replace"
3737
or
38-
name = "match" and exists(mcn.getAPropertyRead())
38+
name = ["match", "matchAll"] and exists(mcn.getAPropertyRead())
3939
)
4040
)
4141
}

javascript/ql/test/experimental/Security/CWE-918/SSRF.expected

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ nodes
5151
| check-regex.js:41:13:41:43 | "test.c ... tainted |
5252
| check-regex.js:41:27:41:43 | req.query.tainted |
5353
| check-regex.js:41:27:41:43 | req.query.tainted |
54+
| check-regex.js:61:15:61:42 | baseURL ... tainted |
55+
| check-regex.js:61:15:61:42 | baseURL ... tainted |
56+
| check-regex.js:61:25:61:42 | req.params.tainted |
57+
| check-regex.js:61:25:61:42 | req.params.tainted |
5458
| check-validator.js:15:15:15:45 | "test.c ... tainted |
5559
| check-validator.js:15:15:15:45 | "test.c ... tainted |
5660
| check-validator.js:15:29:15:45 | req.query.tainted |
@@ -127,6 +131,10 @@ edges
127131
| check-regex.js:41:27:41:43 | req.query.tainted | check-regex.js:41:13:41:43 | "test.c ... tainted |
128132
| check-regex.js:41:27:41:43 | req.query.tainted | check-regex.js:41:13:41:43 | "test.c ... tainted |
129133
| check-regex.js:41:27:41:43 | req.query.tainted | check-regex.js:41:13:41:43 | "test.c ... tainted |
134+
| check-regex.js:61:25:61:42 | req.params.tainted | check-regex.js:61:15:61:42 | baseURL ... tainted |
135+
| check-regex.js:61:25:61:42 | req.params.tainted | check-regex.js:61:15:61:42 | baseURL ... tainted |
136+
| check-regex.js:61:25:61:42 | req.params.tainted | check-regex.js:61:15:61:42 | baseURL ... tainted |
137+
| check-regex.js:61:25:61:42 | req.params.tainted | check-regex.js:61:15:61:42 | baseURL ... tainted |
130138
| check-validator.js:15:29:15:45 | req.query.tainted | check-validator.js:15:15:15:45 | "test.c ... tainted |
131139
| check-validator.js:15:29:15:45 | req.query.tainted | check-validator.js:15:15:15:45 | "test.c ... tainted |
132140
| check-validator.js:15:29:15:45 | req.query.tainted | check-validator.js:15:15:15:45 | "test.c ... tainted |
@@ -166,6 +174,7 @@ edges
166174
| check-regex.js:31:15:31:45 | "test.c ... tainted | check-regex.js:31:29:31:45 | req.query.tainted | check-regex.js:31:15:31:45 | "test.c ... tainted | The URL of this request depends on a user-provided value. |
167175
| check-regex.js:34:15:34:42 | baseURL ... tainted | check-regex.js:34:25:34:42 | req.params.tainted | check-regex.js:34:15:34:42 | baseURL ... tainted | The URL of this request depends on a user-provided value. |
168176
| check-regex.js:41:13:41:43 | "test.c ... tainted | check-regex.js:41:27:41:43 | req.query.tainted | check-regex.js:41:13:41:43 | "test.c ... tainted | The URL of this request depends on a user-provided value. |
177+
| check-regex.js:61:15:61:42 | baseURL ... tainted | check-regex.js:61:25:61:42 | req.params.tainted | check-regex.js:61:15:61:42 | baseURL ... tainted | The URL of this request depends on a user-provided value. |
169178
| check-validator.js:15:15:15:45 | "test.c ... tainted | check-validator.js:15:29:15:45 | req.query.tainted | check-validator.js:15:15:15:45 | "test.c ... tainted | The URL of this request depends on a user-provided value. |
170179
| check-validator.js:27:15:27:45 | "test.c ... tainted | check-validator.js:27:29:27:45 | req.query.tainted | check-validator.js:27:15:27:45 | "test.c ... tainted | The URL of this request depends on a user-provided value. |
171180
| check-validator.js:50:15:50:45 | "test.c ... tainted | check-validator.js:50:29:50:45 | req.query.tainted | check-validator.js:50:15:50:45 | "test.c ... tainted | The URL of this request depends on a user-provided value. |

javascript/ql/test/experimental/Security/CWE-918/check-regex.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ app.get('/check-with-axios', req => {
2525
} else {
2626
axios.get(baseURL + req.params.tainted); // OK
2727
}
28-
28+
2929
// Blacklists are not safe
3030
if (!req.query.tainted.match(/^[/\.%]+$/)) {
3131
axios.get("test.com/" + req.query.tainted); // SSRF
@@ -39,8 +39,29 @@ app.get('/check-with-axios', req => {
3939
}
4040

4141
axios.get("test.com/" + req.query.tainted); // OK - False Positive
42+
43+
if (req.query.tainted.matchAll(/^[0-9a-z]+$/g)) { // letters and numbers
44+
axios.get("test.com/" + req.query.tainted); // OK
45+
}
46+
if (req.query.tainted.matchAll(/^[0-9a-z\-_]+$/g)) { // letters, numbers, - and _
47+
axios.get("test.com/" + req.query.tainted); // OK
48+
}
4249
});
4350

4451
const isValidPath = path => path.match(/^[0-9a-z]+$/);
4552

4653
const isInBlackList = path => path.match(/^[/\.%]+$/);
54+
55+
app.get('/check-with-axios', req => {
56+
const baseURL = "test.com/"
57+
if (isValidPathMatchAll(req.params.tainted) ) {
58+
axios.get(baseURL + req.params.tainted); // OK
59+
}
60+
if (!isValidPathMatchAll(req.params.tainted) ) {
61+
axios.get(baseURL + req.params.tainted); // NOT OK - SSRF
62+
} else {
63+
axios.get(baseURL + req.params.tainted); // OK
64+
}
65+
});
66+
67+
const isValidPathMatchAll = path => path.matchAll(/^[0-9a-z]+$/g);

javascript/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp/IncompleteHostnameRegExp.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@
2525
| tst-IncompleteHostnameRegExp.js:53:14:53:35 | test.example.com$ | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:53:13:53:36 | 'test.' ... e.com$' | here |
2626
| tst-IncompleteHostnameRegExp.js:55:14:55:38 | ^http://test.example.com | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:55:13:55:39 | '^http: ... le.com' | here |
2727
| tst-IncompleteHostnameRegExp.js:59:5:59:20 | foo.example\\.com | This regular expression has an unescaped '.' before 'example\\.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:59:2:59:32 | /^(foo. ... ever)$/ | here |
28+
| tst-IncompleteHostnameRegExp.js:61:18:61:41 | ^http://test.example.com | This regular expression has an unescaped '.' before 'example.com', so it might match more hosts than expected. | tst-IncompleteHostnameRegExp.js:61:17:61:42 | "^http: ... le.com" | here |

javascript/ql/test/query-tests/Security/CWE-020/IncompleteHostnameRegExp/tst-IncompleteHostnameRegExp.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,6 @@
5757
/^http:\/\/(..|...)\.example\.com\/index\.html/; // OK, wildcards are intentional
5858
/^http:\/\/.\.example\.com\/index\.html/; // OK, the wildcard is intentional
5959
/^(foo.example\.com|whatever)$/; // kinda OK - one disjunction doesn't even look like a hostname
60+
61+
if (s.matchAll("^http://test.example.com")) {} // NOT OK
6062
});

javascript/ql/test/query-tests/Security/CWE-020/MissingRegExpAnchor/MissingRegExpAnchor.expected

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,12 @@
5959
| tst-UnanchoredUrlRegExp.js:26:3:26:22 | "^https?://good.com" | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. |
6060
| tst-UnanchoredUrlRegExp.js:35:2:35:32 | /https? ... 0-9]+)/ | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
6161
| tst-UnanchoredUrlRegExp.js:77:11:77:32 | /vimeo\\ ... 0-9]+)/ | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
62+
| tst-UnanchoredUrlRegExp.js:111:50:111:68 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
63+
| tst-UnanchoredUrlRegExp.js:112:61:112:79 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
64+
| tst-UnanchoredUrlRegExp.js:113:50:113:69 | "^https?://good.com" | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. |
65+
| tst-UnanchoredUrlRegExp.js:114:50:114:72 | /^https ... d.com/g | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. |
66+
| tst-UnanchoredUrlRegExp.js:115:50:115:94 | "(^http ... 2.com)" | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. |
67+
| tst-UnanchoredUrlRegExp.js:116:50:116:93 | "(https ... e.com)" | This hostname pattern may match any domain name, as it is missing a '$' or '/' at the end. |
68+
| tst-UnanchoredUrlRegExp.js:117:50:117:59 | "good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
69+
| tst-UnanchoredUrlRegExp.js:118:50:118:68 | "https?://good.com" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |
70+
| tst-UnanchoredUrlRegExp.js:119:50:119:73 | "https? ... m:8080" | When this is used as a regular expression on a URL, it may match anywhere, and arbitrary hosts may come before or after it. |

javascript/ql/test/query-tests/Security/CWE-020/MissingRegExpAnchor/tst-UnanchoredUrlRegExp.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,27 @@
105105

106106
/\.com|\.org/; // OK, has no domain name
107107
/example\.com|whatever/; // OK, the other disjunction doesn't match a hostname
108+
109+
// MatchAll test cases:
110+
// Vulnerable patterns
111+
if ("http://evil.com/?http://good.com".matchAll("https?://good.com")) {} // NOT OK
112+
if ("http://evil.com/?http://good.com".matchAll(new RegExp("https?://good.com"))) {} // NOT OK
113+
if ("http://evil.com/?http://good.com".matchAll("^https?://good.com")) {} // NOT OK - missing post-anchor
114+
if ("http://evil.com/?http://good.com".matchAll(/^https?:\/\/good.com/g)) {} // NOT OK - missing post-anchor
115+
if ("http://evil.com/?http://good.com".matchAll("(^https?://good1.com)|(^https?://good2.com)")) {} // NOT OK - missing post-anchor
116+
if ("http://evil.com/?http://good.com".matchAll("(https?://good.com)|(^https?://goodie.com)")) {} // NOT OK - missing post-anchor
117+
if ("http://evil.com/?http://good.com".matchAll("good.com")) {} // NOT OK - missing protocol
118+
if ("http://evil.com/?http://good.com".matchAll("https?://good.com")) {} // NOT OK
119+
if ("http://evil.com/?http://good.com".matchAll("https?://good.com:8080")) {} // NOT OK
120+
121+
// Non-vulnerable patterns
122+
if ("something".matchAll("other")) {} // OK
123+
if ("something".matchAll("x.commissary")) {} // OK
124+
if ("http://evil.com/?http://good.com".matchAll("^https?://good.com$")) {} // OK
125+
if ("http://evil.com/?http://good.com".matchAll(new RegExp("^https?://good.com$"))) {} // OK
126+
if ("http://evil.com/?http://good.com".matchAll("^https?://good.com/$")) {} // OK
127+
if ("http://evil.com/?http://good.com".matchAll(/^https?:\/\/good.com\/$/)) {} // OK
128+
if ("http://evil.com/?http://good.com".matchAll("(^https?://good1.com$)|(^https?://good2.com$)")) {} // OK
129+
if ("http://evil.com/?http://good.com".matchAll("(https?://good.com$)|(^https?://goodie.com$)")) {} // OK
130+
108131
});

javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,6 +2237,19 @@ nodes
22372237
| normalizedPaths.js:408:38:408:59 | req.que ... it('/') |
22382238
| normalizedPaths.js:408:38:408:59 | req.que ... it('/') |
22392239
| normalizedPaths.js:408:38:408:59 | req.que ... it('/') |
2240+
| normalizedPaths.js:412:7:412:46 | path |
2241+
| normalizedPaths.js:412:7:412:46 | path |
2242+
| normalizedPaths.js:412:14:412:46 | pathMod ... uery.x) |
2243+
| normalizedPaths.js:412:14:412:46 | pathMod ... uery.x) |
2244+
| normalizedPaths.js:412:35:412:45 | req.query.x |
2245+
| normalizedPaths.js:412:35:412:45 | req.query.x |
2246+
| normalizedPaths.js:412:35:412:45 | req.query.x |
2247+
| normalizedPaths.js:415:19:415:22 | path |
2248+
| normalizedPaths.js:415:19:415:22 | path |
2249+
| normalizedPaths.js:415:19:415:22 | path |
2250+
| normalizedPaths.js:426:21:426:24 | path |
2251+
| normalizedPaths.js:426:21:426:24 | path |
2252+
| normalizedPaths.js:426:21:426:24 | path |
22402253
| other-fs-libraries.js:9:7:9:48 | path |
22412254
| other-fs-libraries.js:9:7:9:48 | path |
22422255
| other-fs-libraries.js:9:7:9:48 | path |
@@ -7524,6 +7537,20 @@ edges
75247537
| normalizedPaths.js:408:38:408:59 | req.que ... it('/') | normalizedPaths.js:408:19:408:60 | pathMod ... t('/')) |
75257538
| normalizedPaths.js:408:38:408:59 | req.que ... it('/') | normalizedPaths.js:408:19:408:60 | pathMod ... t('/')) |
75267539
| normalizedPaths.js:408:38:408:59 | req.que ... it('/') | normalizedPaths.js:408:19:408:60 | pathMod ... t('/')) |
7540+
| normalizedPaths.js:412:7:412:46 | path | normalizedPaths.js:415:19:415:22 | path |
7541+
| normalizedPaths.js:412:7:412:46 | path | normalizedPaths.js:415:19:415:22 | path |
7542+
| normalizedPaths.js:412:7:412:46 | path | normalizedPaths.js:415:19:415:22 | path |
7543+
| normalizedPaths.js:412:7:412:46 | path | normalizedPaths.js:415:19:415:22 | path |
7544+
| normalizedPaths.js:412:7:412:46 | path | normalizedPaths.js:426:21:426:24 | path |
7545+
| normalizedPaths.js:412:7:412:46 | path | normalizedPaths.js:426:21:426:24 | path |
7546+
| normalizedPaths.js:412:7:412:46 | path | normalizedPaths.js:426:21:426:24 | path |
7547+
| normalizedPaths.js:412:7:412:46 | path | normalizedPaths.js:426:21:426:24 | path |
7548+
| normalizedPaths.js:412:14:412:46 | pathMod ... uery.x) | normalizedPaths.js:412:7:412:46 | path |
7549+
| normalizedPaths.js:412:14:412:46 | pathMod ... uery.x) | normalizedPaths.js:412:7:412:46 | path |
7550+
| normalizedPaths.js:412:35:412:45 | req.query.x | normalizedPaths.js:412:14:412:46 | pathMod ... uery.x) |
7551+
| normalizedPaths.js:412:35:412:45 | req.query.x | normalizedPaths.js:412:14:412:46 | pathMod ... uery.x) |
7552+
| normalizedPaths.js:412:35:412:45 | req.query.x | normalizedPaths.js:412:14:412:46 | pathMod ... uery.x) |
7553+
| normalizedPaths.js:412:35:412:45 | req.query.x | normalizedPaths.js:412:14:412:46 | pathMod ... uery.x) |
75277554
| other-fs-libraries.js:9:7:9:48 | path | other-fs-libraries.js:11:19:11:22 | path |
75287555
| other-fs-libraries.js:9:7:9:48 | path | other-fs-libraries.js:11:19:11:22 | path |
75297556
| other-fs-libraries.js:9:7:9:48 | path | other-fs-libraries.js:11:19:11:22 | path |
@@ -10539,6 +10566,8 @@ edges
1053910566
| normalizedPaths.js:399:21:399:24 | path | normalizedPaths.js:385:35:385:45 | req.query.x | normalizedPaths.js:399:21:399:24 | path | This path depends on a $@. | normalizedPaths.js:385:35:385:45 | req.query.x | user-provided value |
1054010567
| normalizedPaths.js:407:19:407:67 | pathMod ... t('/')) | normalizedPaths.js:407:45:407:55 | req.query.x | normalizedPaths.js:407:19:407:67 | pathMod ... t('/')) | This path depends on a $@. | normalizedPaths.js:407:45:407:55 | req.query.x | user-provided value |
1054110568
| normalizedPaths.js:408:19:408:60 | pathMod ... t('/')) | normalizedPaths.js:408:38:408:48 | req.query.x | normalizedPaths.js:408:19:408:60 | pathMod ... t('/')) | This path depends on a $@. | normalizedPaths.js:408:38:408:48 | req.query.x | user-provided value |
10569+
| normalizedPaths.js:415:19:415:22 | path | normalizedPaths.js:412:35:412:45 | req.query.x | normalizedPaths.js:415:19:415:22 | path | This path depends on a $@. | normalizedPaths.js:412:35:412:45 | req.query.x | user-provided value |
10570+
| normalizedPaths.js:426:21:426:24 | path | normalizedPaths.js:412:35:412:45 | req.query.x | normalizedPaths.js:426:21:426:24 | path | This path depends on a $@. | normalizedPaths.js:412:35:412:45 | req.query.x | user-provided value |
1054210571
| other-fs-libraries.js:11:19:11:22 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:11:19:11:22 | path | This path depends on a $@. | other-fs-libraries.js:9:24:9:30 | req.url | user-provided value |
1054310572
| other-fs-libraries.js:12:27:12:30 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:12:27:12:30 | path | This path depends on a $@. | other-fs-libraries.js:9:24:9:30 | req.url | user-provided value |
1054410573
| other-fs-libraries.js:13:24:13:27 | path | other-fs-libraries.js:9:24:9:30 | req.url | other-fs-libraries.js:13:24:13:27 | path | This path depends on a $@. | other-fs-libraries.js:9:24:9:30 | req.url | user-provided value |

javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/normalizedPaths.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,3 +407,25 @@ app.get('/join-spread', (req, res) => {
407407
fs.readFileSync(pathModule.join('foo', ...req.query.x.split('/'))); // NOT OK
408408
fs.readFileSync(pathModule.join(...req.query.x.split('/'))); // NOT OK
409409
});
410+
411+
app.get('/dotdot-matchAll-regexp', (req, res) => {
412+
let path = pathModule.normalize(req.query.x);
413+
if (pathModule.isAbsolute(path))
414+
return;
415+
fs.readFileSync(path); // NOT OK
416+
if (!path.matchAll(/\./)) {
417+
fs.readFileSync(path); // OK
418+
}
419+
if (!path.matchAll(/\.\./)) {
420+
fs.readFileSync(path); // OK
421+
}
422+
if (!path.matchAll(/\.\.\//)) {
423+
fs.readFileSync(path); // OK
424+
}
425+
if (!path.matchAll(/\.\.\/foo/)) {
426+
fs.readFileSync(path); // NOT OK
427+
}
428+
if (!path.matchAll(/(\.\.\/|\.\.\\)/)) {
429+
fs.readFileSync(path); // OK
430+
}
431+
});

0 commit comments

Comments
 (0)