Skip to content

Commit 315cae2

Browse files
committed
Swift: Tests for regex injection query.
1 parent b41fd52 commit 315cae2

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
edges
2+
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:118:19:118:19 | taintedString |
3+
nodes
4+
| tests.swift:93:22:93:46 | call to String.init(contentsOf:) | semmle.label | call to String.init(contentsOf:) |
5+
| tests.swift:118:19:118:19 | taintedString | semmle.label | taintedString |
6+
subpaths
7+
#select
8+
| tests.swift:118:19:118:19 | taintedString | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | tests.swift:118:19:118:19 | taintedString | This regular expression is constructed from a $@. | tests.swift:93:22:93:46 | call to String.init(contentsOf:) | user-provided value |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
queries/Security/CWE-730/RegexInjection.ql
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
2+
// --- stubs ---
3+
4+
struct URL {
5+
init?(string: String) {}
6+
}
7+
8+
struct AnyRegexOutput {
9+
}
10+
11+
protocol RegexComponent<RegexOutput> {
12+
associatedtype RegexOutput
13+
}
14+
15+
struct Regex<Output> : RegexComponent {
16+
struct Match {
17+
}
18+
19+
init(_ pattern: String) throws where Output == AnyRegexOutput { }
20+
21+
func firstMatch(in string: String) throws -> Regex<Output>.Match? { return nil}
22+
23+
typealias RegexOutput = Output
24+
}
25+
26+
extension RangeReplaceableCollection {
27+
mutating func replace<Replacement>(_ regex: some RegexComponent, with replacement: Replacement, maxReplacements: Int = .max) where Replacement : Collection, Replacement.Element == Character { }
28+
}
29+
30+
extension StringProtocol {
31+
func replacingOccurrences<Target, Replacement>(of target: Target, with replacement: Replacement, options: String.CompareOptions = [], range searchRange: Range<Self.Index>? = nil) -> String where Target : StringProtocol, Replacement : StringProtocol { return "" }
32+
}
33+
34+
extension String : RegexComponent {
35+
typealias CompareOptions = NSString.CompareOptions
36+
typealias Output = Substring
37+
typealias RegexOutput = String.Output
38+
}
39+
40+
class NSObject {
41+
}
42+
43+
class NSString : NSObject {
44+
struct CompareOptions : OptionSet {
45+
var rawValue: UInt
46+
47+
static var regularExpression: NSString.CompareOptions { get { return CompareOptions(rawValue: 1) } }
48+
}
49+
50+
convenience init(string aString: String) { self.init() }
51+
52+
func replacingOccurrences(of target: String, with replacement: String, options: NSString.CompareOptions = [], range searchRange: NSRange) -> String { return "" }
53+
54+
var length: Int { get { return 0 } }
55+
}
56+
57+
struct _NSRange {
58+
init(location: Int, length: Int) { }
59+
}
60+
61+
typealias NSRange = _NSRange
62+
63+
func NSMakeRange(_ loc: Int, _ len: Int) -> NSRange { return NSRange(location: loc, length: len) }
64+
65+
class NSTextCheckingResult : NSObject {
66+
}
67+
68+
class NSRegularExpression : NSObject {
69+
struct Options : OptionSet {
70+
var rawValue: UInt
71+
}
72+
73+
struct MatchingOptions : OptionSet {
74+
var rawValue: UInt
75+
}
76+
77+
init(pattern: String, options: NSRegularExpression.Options = []) throws { }
78+
79+
func firstMatch(in string: String, options: NSRegularExpression.MatchingOptions = [], range: NSRange) -> NSTextCheckingResult? { return nil }
80+
}
81+
82+
extension String {
83+
init(contentsOf: URL) {
84+
let data = ""
85+
self.init(data)
86+
}
87+
}
88+
89+
// --- tests ---
90+
91+
func regexInjectionTests(cond: Bool, varString: String, myUrl: URL) throws {
92+
let constString = ".*"
93+
let taintedString = String(contentsOf: myUrl) // tainted
94+
95+
// --- Regex ---
96+
97+
_ = try Regex(constString).firstMatch(in: varString)
98+
_ = try Regex(varString).firstMatch(in: varString)
99+
_ = try Regex(taintedString).firstMatch(in: varString) // BAD [NOT DETECTED]
100+
101+
_ = try Regex("(a|" + constString + ")").firstMatch(in: varString)
102+
_ = try Regex("(a|" + taintedString + ")").firstMatch(in: varString) // BAD [NOT DETECTED]
103+
_ = try Regex("(a|\(constString))").firstMatch(in: varString)
104+
_ = try Regex("(a|\(taintedString))").firstMatch(in: varString) // BAD [NOT DETECTED]
105+
106+
_ = try Regex(cond ? constString : constString).firstMatch(in: varString)
107+
_ = try Regex(cond ? taintedString : constString).firstMatch(in: varString) // BAD [NOT DETECTED]
108+
_ = try Regex(cond ? constString : taintedString).firstMatch(in: varString) // BAD [NOT DETECTED]
109+
110+
_ = try (cond ? Regex(constString) : Regex(constString)).firstMatch(in: varString)
111+
_ = try (cond ? Regex(taintedString) : Regex(constString)).firstMatch(in: varString) // BAD [NOT DETECTED]
112+
_ = try (cond ? Regex(constString) : Regex(taintedString)).firstMatch(in: varString) // BAD [NOT DETECTED]
113+
114+
// --- RangeReplaceableCollection ---
115+
116+
var inputVar = varString
117+
inputVar.replace(constString, with: "")
118+
inputVar.replace(taintedString, with: "") // BAD
119+
inputVar.replace(constString, with: taintedString)
120+
121+
// --- StringProtocol ---
122+
123+
_ = inputVar.replacingOccurrences(of: constString, with: "", options: .regularExpression)
124+
_ = inputVar.replacingOccurrences(of: taintedString, with: "", options: .regularExpression) // BAD [NOT DETECTED]
125+
126+
// --- NSRegularExpression ---
127+
128+
_ = try NSRegularExpression(pattern: constString).firstMatch(in: varString, range: NSMakeRange(0, varString.utf16.count))
129+
_ = try NSRegularExpression(pattern: taintedString).firstMatch(in: varString, range: NSMakeRange(0, varString.utf16.count)) // BAD [NOT DETECTED]
130+
131+
// --- NSString ---
132+
133+
let nsString = NSString(string: varString)
134+
_ = nsString.replacingOccurrences(of: constString, with: "", options: .regularExpression, range: NSMakeRange(0, nsString.length))
135+
_ = nsString.replacingOccurrences(of: taintedString, with: "", options: .regularExpression, range: NSMakeRange(0, nsString.length)) // BAD [NOT DETECTED]
136+
}

0 commit comments

Comments
 (0)