2
2
// --- stubs ---
3
3
4
4
struct URL {
5
- init ? ( string: String ) { }
5
+ init ? ( string: String ) { }
6
6
}
7
7
8
8
struct AnyRegexOutput {
@@ -12,20 +12,20 @@ protocol RegexComponent {
12
12
}
13
13
14
14
struct Regex < Output> : RegexComponent {
15
- struct Match {
16
- }
15
+ struct Match {
16
+ }
17
17
18
- init ( _ pattern: String ) throws where Output == AnyRegexOutput { }
18
+ init ( _ pattern: String ) throws where Output == AnyRegexOutput { }
19
19
20
- func firstMatch( in string: String ) throws -> Regex < Output > . Match ? { return nil }
21
- func prefixMatch( in string: String ) throws -> Regex < Output > . Match ? { return nil }
22
- func wholeMatch( in string: String ) throws -> Regex < Output > . Match ? { return nil }
20
+ func firstMatch( in string: String ) throws -> Regex < Output > . Match ? { return nil }
21
+ func prefixMatch( in string: String ) throws -> Regex < Output > . Match ? { return nil }
22
+ func wholeMatch( in string: String ) throws -> Regex < Output > . Match ? { return nil }
23
23
24
- typealias RegexOutput = Output
24
+ typealias RegexOutput = Output
25
25
}
26
26
27
27
extension String {
28
- init ( contentsOf: URL ) {
28
+ init ( contentsOf: URL ) {
29
29
let data = " "
30
30
self . init ( data)
31
31
}
@@ -36,88 +36,88 @@ extension String {
36
36
// the focus for these tests is different vulnerable and non-vulnerable regexp strings.
37
37
38
38
func myRegexpVariantsTests( myUrl: URL ) throws {
39
- let tainted = String ( contentsOf: myUrl) // tainted
39
+ let tainted = String ( contentsOf: myUrl) // tainted
40
40
41
41
// basic cases:
42
42
// attack string: "a" x lots + "!"
43
43
44
- _ = try Regex ( " .* " ) . firstMatch ( in: tainted) // $ regex=.* input=tainted
44
+ _ = try Regex ( " .* " ) . firstMatch ( in: tainted) // $ regex=.* input=tainted
45
45
46
- _ = try Regex ( " a*b " ) . firstMatch ( in: tainted) // $ regex=a*b input=tainted
47
- _ = try Regex ( " (a*)b " ) . firstMatch ( in: tainted) // $ regex=(a*)b input=tainted
48
- _ = try Regex ( " (a)*b " ) . firstMatch ( in: tainted) // $ regex=(a)*b input=tainted
49
- _ = try Regex ( " (a*)*b " ) . firstMatch ( in: tainted) // $ regex=(a*)*b input=tainted redos-vulnerable=
50
- _ = try Regex ( " ((a*)*b) " ) . firstMatch ( in: tainted) // $ regex=((a*)*b) input=tainted redos-vulnerable=
46
+ _ = try Regex ( " a*b " ) . firstMatch ( in: tainted) // $ regex=a*b input=tainted
47
+ _ = try Regex ( " (a*)b " ) . firstMatch ( in: tainted) // $ regex=(a*)b input=tainted
48
+ _ = try Regex ( " (a)*b " ) . firstMatch ( in: tainted) // $ regex=(a)*b input=tainted
49
+ _ = try Regex ( " (a*)*b " ) . firstMatch ( in: tainted) // $ regex=(a*)*b input=tainted redos-vulnerable=
50
+ _ = try Regex ( " ((a*)*b) " ) . firstMatch ( in: tainted) // $ regex=((a*)*b) input=tainted redos-vulnerable=
51
51
52
- _ = try Regex ( " (a|aa?)b " ) . firstMatch ( in: tainted) // $ regex=(a|aa?)b input=tainted
53
- _ = try Regex ( " (a|aa?)*b " ) . firstMatch ( in: tainted) // $ regex=(a|aa?)*b input=tainted redos-vulnerable=
52
+ _ = try Regex ( " (a|aa?)b " ) . firstMatch ( in: tainted) // $ regex=(a|aa?)b input=tainted
53
+ _ = try Regex ( " (a|aa?)*b " ) . firstMatch ( in: tainted) // $ regex=(a|aa?)*b input=tainted redos-vulnerable=
54
54
55
55
// from the qhelp:
56
- // attack string: "_" x lots + "!"
56
+ // attack string: "_" x lots + "!"
57
57
58
- _ = try Regex ( " ^_(__|.)+_$ " ) . firstMatch ( in: tainted) // $ regex=^_(__|.)+_$ input=tainted redos-vulnerable=
59
- _ = try Regex ( " ^_(__|[^_])+_$ " ) . firstMatch ( in: tainted) // $ regex=^_(__|[^_])+_$ input=tainted
58
+ _ = try Regex ( " ^_(__|.)+_$ " ) . firstMatch ( in: tainted) // $ regex=^_(__|.)+_$ input=tainted redos-vulnerable=
59
+ _ = try Regex ( " ^_(__|[^_])+_$ " ) . firstMatch ( in: tainted) // $ regex=^_(__|[^_])+_$ input=tainted
60
60
61
61
// real world cases:
62
62
63
63
// Adapted from marked (https://github.com/markedjs/marked), which is licensed
64
64
// under the MIT license; see file licenses/marked-LICENSE.
65
65
// GOOD
66
- _ = try Regex ( #"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"# ) . firstMatch ( in: tainted) // $ SPURIOUS: redos-vulnerable=
67
- // BAD
66
+ _ = try Regex ( #"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"# ) . firstMatch ( in: tainted) // $ SPURIOUS: redos-vulnerable=
67
+ // BAD
68
68
// attack string: "_" + "__".repeat(100)
69
- _ = try Regex ( #"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"# ) . wholeMatch ( in: tainted) // $ redos-vulnerable=
69
+ _ = try Regex ( #"^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)"# ) . wholeMatch ( in: tainted) // $ redos-vulnerable=
70
70
71
71
// GOOD
72
72
// Adapted from marked (https://github.com/markedjs/marked), which is licensed
73
73
// under the MIT license; see file licenses/marked-LICENSE.
74
- _ = try Regex ( #"^\b_((?:__|[^_])+?)_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)"# ) . firstMatch ( in: tainted)
74
+ _ = try Regex ( #"^\b_((?:__|[^_])+?)_\b|^\*((?:\*\*|[^*])+?)\*(?!\*)"# ) . firstMatch ( in: tainted)
75
75
76
76
// GOOD - there is no witness in the end that could cause the regexp to not match
77
77
// Adapted from brace-expansion (https://github.com/juliangruber/brace-expansion),
78
78
// which is licensed under the MIT license; see file licenses/brace-expansion-LICENSE.
79
- _ = try Regex ( " (.*,)+.+ " ) . firstMatch ( in: tainted)
79
+ _ = try Regex ( " (.*,)+.+ " ) . firstMatch ( in: tainted)
80
80
81
81
// BAD
82
82
// attack string: " '" + "\\\\".repeat(100)
83
83
// Adapted from CodeMirror (https://github.com/codemirror/codemirror),
84
84
// which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE.
85
- _ = try Regex ( #"^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
85
+ _ = try Regex ( #"^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
86
86
87
87
// GOOD
88
88
// Adapted from jest (https://github.com/facebook/jest), which is licensed
89
89
// under the MIT license; see file licenses/jest-LICENSE.
90
- _ = try Regex ( #"^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*"# ) . firstMatch ( in: tainted)
90
+ _ = try Regex ( #"^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*"# ) . firstMatch ( in: tainted)
91
91
92
92
// BAD
93
93
// attack string: "/" + "\\/a".repeat(100)
94
94
// Adapted from ANodeBlog (https://github.com/gefangshuai/ANodeBlog),
95
95
// which is licensed under the Apache License 2.0; see file licenses/ANodeBlog-LICENSE.
96
- _ = try Regex ( #"\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
96
+ _ = try Regex ( #"\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
97
97
98
98
// BAD
99
99
// attack string: "##".repeat(100) + "\na"
100
100
// Adapted from CodeMirror (https://github.com/codemirror/codemirror),
101
101
// which is licensed under the MIT license; see file licenses/CodeMirror-LICENSE.
102
- _ = try Regex ( #"^([\s\[\{\(]|#.*)*$"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
102
+ _ = try Regex ( #"^([\s\[\{\(]|#.*)*$"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
103
103
104
104
// BAD
105
105
// attack string: "a" + "[]".repeat(100) + ".b\n"
106
106
// Adapted from Knockout (https://github.com/knockout/knockout), which is
107
107
// licensed under the MIT license; see file licenses/knockout-LICENSE
108
- _ = try Regex ( #"^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
108
+ _ = try Regex ( #"^[\_$a-z][\_$a-z0-9]*(\[.*?\])*(\.[\_$a-z][\_$a-z0-9]*(\[.*?\])*)*$"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
109
109
110
110
// BAD
111
111
// attack string: "[" + "][".repeat(100) + "]!"
112
112
// Adapted from Prototype.js (https://github.com/prototypejs/prototype), which
113
113
// is licensed under the MIT license; see file licenses/Prototype.js-LICENSE.
114
- _ = try Regex ( #"(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
114
+ _ = try Regex ( #"(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
115
115
116
116
// BAD
117
117
// attack string: "'" + "\\a".repeat(100) + '"'
118
118
// Adapted from Prism (https://github.com/PrismJS/prism), which is licensed
119
119
// under the MIT license; see file licenses/Prism-LICENSE.
120
- _ = try Regex ( #"("|')(\\?.)*?\1"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
120
+ _ = try Regex ( #"("|')(\\?.)*?\1"# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
121
121
122
122
// more cases:
123
123
@@ -148,7 +148,7 @@ func myRegexpVariantsTests(myUrl: URL) throws {
148
148
149
149
// GOOD
150
150
_ = try Regex ( #"([\w.]+)*"# ) . firstMatch ( in: tainted)
151
- // BAD
151
+ // BAD
152
152
// attack string: "a" x lots + "!"
153
153
_ = try Regex ( #"([\w.]+)*"# ) . wholeMatch ( in: tainted) // $ MISSING: redos-vulnerable=
154
154
@@ -214,7 +214,7 @@ func myRegexpVariantsTests(myUrl: URL) throws {
214
214
215
215
// BAD
216
216
// attack string: "5" x lots + "!"
217
- _ = try Regex ( #"((\d|\d)*)""# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
217
+ _ = try Regex ( #"((\d|\d)*)""# ) . firstMatch ( in: tainted) // $ redos-vulnerable=
218
218
219
219
// BAD
220
220
// attack string: "0" x lots + "!"
@@ -262,7 +262,7 @@ func myRegexpVariantsTests(myUrl: URL) throws {
262
262
263
263
// GOOD - there is no witness in the end that could cause the regexp to not match
264
264
_ = try Regex ( #"(\d+(X\d+)?)+"# ) . firstMatch ( in: tainted)
265
- // BAD
265
+ // BAD
266
266
// attack string: "0" x lots + "!"
267
267
_ = try Regex ( #"(\d+(X\d+)?)+"# ) . wholeMatch ( in: tainted) // $ MISSING: redos-vulnerable=
268
268
@@ -305,7 +305,7 @@ func myRegexpVariantsTests(myUrl: URL) throws {
305
305
306
306
// GOOD
307
307
_ = try Regex ( " (a+)+aaaaa*a+ " ) . firstMatch ( in: tainted)
308
- // BAD
308
+ // BAD
309
309
// attack string: "a" x lots + "!"
310
310
_ = try Regex ( " (a+)+aaaaa*a+ " ) . wholeMatch ( in: tainted) // $ MISSING: redos-vulnerable=
311
311
@@ -333,7 +333,7 @@ func myRegexpVariantsTests(myUrl: URL) throws {
333
333
334
334
// GOOD
335
335
_ = try Regex ( " (([^X]b)+)*($|[^X]b) " ) . firstMatch ( in: tainted)
336
- // BAD
336
+ // BAD
337
337
// attack string: "b" x lots + "!"
338
338
_ = try Regex ( " (([^X]b)+)*($|[^X]b) " ) . wholeMatch ( in: tainted) // $ MISSING: redos-vulnerable=
339
339
@@ -544,7 +544,7 @@ func myRegexpVariantsTests(myUrl: URL) throws {
544
544
545
545
// GOOD
546
546
_ = try Regex ( #"("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)"# ) . firstMatch ( in: tainted)
547
- // BAD
547
+ // BAD
548
548
// attack string: "##" x lots + "\na"
549
549
_ = try Regex ( #"("[^"]*?"|[^"\s]+)+(?=\s*|\s*$)"# ) . wholeMatch ( in: tainted) // $ MISSING: redos-vulnerable=
550
550
0 commit comments