Skip to content

Commit 1386435

Browse files
authored
Merge pull request github#10757 from geoffw0/sqlinject
Swift: Query for SQL injection
2 parents 2e9c8c7 + 661106c commit 1386435

File tree

8 files changed

+546
-0
lines changed

8 files changed

+546
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
7+
<p>
8+
If a database query (such as a SQL query) is built from user-provided data without sufficient sanitization, a user may be able to run malicious database queries. An attacker can craft the part of the query they control to change the overall meaning of the query.
9+
</p>
10+
11+
</overview>
12+
<recommendation>
13+
14+
<p>
15+
Most database connector libraries offer a way to safely embed untrusted data into a query using query parameters or prepared statements. You should use these features to build queries, rather than string concatenation or similar methods without sufficient sanitization.
16+
</p>
17+
18+
</recommendation>
19+
<example>
20+
21+
<p>In the following example, a SQL query is prepared using string interpolation to directly include a user-controlled value <code>userControlledString</code> in the query. An attacker could craft <code>userControlledString</code> to change the overall meaning of the SQL query.
22+
</p>
23+
24+
<sample src="SqlInjectionBad.swift" />
25+
26+
<p>A better way to do this is with a prepared statement, binding <code>userControlledString</code> to a parameter of that statement. An attacker who controls <code>userControlledString</code> now cannot change the overall meaning of the query.
27+
</p>
28+
29+
<sample src="SqlInjectionGood.swift" />
30+
31+
</example>
32+
<references>
33+
34+
<li>Wikipedia: <a href="https://en.wikipedia.org/wiki/SQL_injection">SQL injection</a>.</li>
35+
<li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html">SQL Injection Prevention Cheat Sheet</a>.</li>
36+
37+
</references>
38+
</qhelp>
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/**
2+
* @name Database query built from user-controlled sources
3+
* @description Building a database query from user-controlled sources is vulnerable to insertion of malicious code by the user.
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @security-severity 8.8
7+
* @precision high
8+
* @id swift/sql-injection
9+
* @tags security
10+
* external/cwe/cwe-089
11+
*/
12+
13+
import swift
14+
import codeql.swift.dataflow.DataFlow
15+
import codeql.swift.dataflow.TaintTracking
16+
import codeql.swift.dataflow.FlowSources
17+
import DataFlow::PathGraph
18+
19+
/**
20+
* A `DataFlow::Node` that is a sink for a SQL string to be executed.
21+
*/
22+
abstract class SqlSink extends DataFlow::Node { }
23+
24+
/**
25+
* A sink for the sqlite3 C API.
26+
*/
27+
class CApiSqlSink extends SqlSink {
28+
CApiSqlSink() {
29+
// `sqlite3_exec` and variants of `sqlite3_prepare`.
30+
exists(AbstractFunctionDecl f, CallExpr call |
31+
f.getName() =
32+
[
33+
"sqlite3_exec(_:_:_:_:_:)", "sqlite3_prepare(_:_:_:_:_:)",
34+
"sqlite3_prepare_v2(_:_:_:_:_:)", "sqlite3_prepare_v3(_:_:_:_:_:_:)",
35+
"sqlite3_prepare16(_:_:_:_:_:)", "sqlite3_prepare16_v2(_:_:_:_:_:)",
36+
"sqlite3_prepare16_v3(_:_:_:_:_:_:)"
37+
] and
38+
call.getStaticTarget() = f and
39+
call.getArgument(1).getExpr() = this.asExpr()
40+
)
41+
}
42+
}
43+
44+
/**
45+
* A sink for the SQLite.swift library.
46+
*/
47+
class SQLiteSwiftSqlSink extends SqlSink {
48+
SQLiteSwiftSqlSink() {
49+
// Variants of `Connection.execute`, `connection.prepare` and `connection.scalar`.
50+
exists(ClassDecl c, AbstractFunctionDecl f, CallExpr call |
51+
c.getName() = "Connection" and
52+
c.getAMember() = f and
53+
f.getName() = ["execute(_:)", "prepare(_:_:)", "run(_:_:)", "scalar(_:_:)"] and
54+
call.getStaticTarget() = f and
55+
call.getArgument(0).getExpr() = this.asExpr()
56+
)
57+
or
58+
// String argument to the `Statement` constructor.
59+
exists(ClassDecl c, AbstractFunctionDecl f, CallExpr call |
60+
c.getName() = "Statement" and
61+
c.getAMember() = f and
62+
f.getName() = "init(_:_:)" and
63+
call.getStaticTarget() = f and
64+
call.getArgument(1).getExpr() = this.asExpr()
65+
)
66+
}
67+
}
68+
69+
/**
70+
* A taint configuration for tainted data that reaches a SQL sink.
71+
*/
72+
class SqlInjectionConfig extends TaintTracking::Configuration {
73+
SqlInjectionConfig() { this = "SqlInjectionConfig" }
74+
75+
override predicate isSource(DataFlow::Node node) { node instanceof RemoteFlowSource }
76+
77+
override predicate isSink(DataFlow::Node node) { node instanceof SqlSink }
78+
}
79+
80+
from SqlInjectionConfig config, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
81+
where config.hasFlowPath(sourceNode, sinkNode)
82+
select sinkNode.getNode(), sourceNode, sinkNode, "This query depends on a $@.",
83+
sourceNode.getNode(), "user-provided value"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
let unsafeQuery = "SELECT * FROM users WHERE username='\(userControlledString)'" // BAD
2+
3+
try db.execute(unsafeQuery)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
let safeQuery = "SELECT * FROM users WHERE username=?"
2+
3+
let stmt = try db.prepare(safeQuery, userControlledString) // GOOD
4+
try stmt2.run()
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
2+
// --- stubs ---
3+
4+
struct URL
5+
{
6+
init?(string: String) {}
7+
init?(string: String, relativeTo: URL?) {}
8+
}
9+
10+
extension String {
11+
init(contentsOf: URL) throws {
12+
var data = ""
13+
14+
// ...
15+
16+
self.init(data)
17+
}
18+
}
19+
20+
public protocol Binding {}
21+
22+
extension String: Binding {}
23+
24+
class Statement {
25+
fileprivate let connection: Connection
26+
27+
init(_ connection: Connection, _ SQL: String) throws { self.connection = connection}
28+
29+
public func bind(_ values: Binding?...) -> Statement { return Statement(connection, "") }
30+
public func bind(_ values: [Binding?]) -> Statement { return Statement(connection, "") }
31+
public func bind(_ values: [String: Binding?]) -> Statement { return Statement(connection, "") }
32+
33+
@discardableResult public func run(_ bindings: Binding?...) throws -> Statement { return Statement(connection, "") }
34+
@discardableResult public func run(_ bindings: [Binding?]) throws -> Statement { return Statement(connection, "") }
35+
@discardableResult public func run(_ bindings: [String: Binding?]) throws -> Statement { return Statement(connection, "") }
36+
37+
public func scalar(_ bindings: Binding?...) throws -> Binding? { return nil }
38+
public func scalar(_ bindings: [Binding?]) throws -> Binding? { return nil }
39+
public func scalar(_ bindings: [String: Binding?]) throws -> Binding? { return nil }
40+
}
41+
42+
class Connection {
43+
public func execute(_ SQL: String) throws { }
44+
45+
public func prepare(_ statement: String, _ bindings: Binding?...) throws -> Statement { return Statement(self, "") }
46+
public func prepare(_ statement: String, _ bindings: [Binding?]) throws -> Statement { return Statement(self, "") }
47+
public func prepare(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement { return Statement(self, "") }
48+
49+
@discardableResult public func run(_ statement: String, _ bindings: Binding?...) throws -> Statement { return Statement(self, "") }
50+
@discardableResult public func run(_ statement: String, _ bindings: [Binding?]) throws -> Statement { return Statement(self, "") }
51+
@discardableResult public func run(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement { return Statement(self, "") }
52+
53+
public func scalar(_ statement: String, _ bindings: Binding?...) throws -> Binding? { return nil }
54+
public func scalar(_ statement: String, _ bindings: [Binding?]) throws -> Binding? { return nil }
55+
public func scalar(_ statement: String, _ bindings: [String: Binding?]) throws -> Binding? { return nil }
56+
}
57+
58+
// --- tests ---
59+
60+
func test_sqlite_swift_api(db: Connection) {
61+
let localString = "user"
62+
let remoteString = try! String(contentsOf: URL(string: "http://example.com/")!)
63+
let remoteNumber = Int(remoteString) ?? 0
64+
65+
let unsafeQuery1 = remoteString
66+
let unsafeQuery2 = "SELECT * FROM users WHERE username='" + remoteString + "'"
67+
let unsafeQuery3 = "SELECT * FROM users WHERE username='\(remoteString)'"
68+
let safeQuery1 = "SELECT * FROM users WHERE username='\(localString)'"
69+
let safeQuery2 = "SELECT * FROM users WHERE username='\(remoteNumber)'"
70+
71+
// --- execute ---
72+
73+
try db.execute(unsafeQuery1) // BAD
74+
try db.execute(unsafeQuery2) // BAD
75+
try db.execute(unsafeQuery3) // BAD
76+
try db.execute(safeQuery1) // GOOD
77+
try db.execute(safeQuery2) // GOOD
78+
79+
// --- prepared statements ---
80+
81+
let varQuery = "SELECT * FROM users WHERE username=?"
82+
83+
let stmt1 = try db.prepare(unsafeQuery3) // BAD
84+
try stmt1.run()
85+
86+
let stmt2 = try db.prepare(varQuery, localString) // GOOD
87+
try stmt2.run()
88+
89+
let stmt3 = try db.prepare(varQuery, remoteString) // GOOD
90+
try stmt3.run()
91+
92+
let stmt4 = Statement(db, localString) // GOOD
93+
stmt4.run()
94+
95+
let stmt5 = Statement(db, remoteString) // BAD
96+
stmt5.run()
97+
98+
// --- more variants ---
99+
100+
let stmt6 = try db.prepare(unsafeQuery1, "") // BAD
101+
try stmt6.run()
102+
103+
let stmt7 = try db.prepare(unsafeQuery1, [""]) // BAD
104+
try stmt7.run()
105+
106+
let stmt8 = try db.prepare(unsafeQuery1, ["username": ""]) // BAD
107+
try stmt8.run()
108+
109+
db.run(unsafeQuery1, "") // BAD
110+
111+
db.run(unsafeQuery1, [""]) // BAD
112+
113+
db.run(unsafeQuery1, ["username": ""]) // BAD
114+
115+
db.scalar(unsafeQuery1, "") // BAD
116+
117+
db.scalar(unsafeQuery1, [""]) // BAD
118+
119+
db.scalar(unsafeQuery1, ["username": ""]) // BAD
120+
121+
let stmt9 = try db.prepare(varQuery) // GOOD
122+
stmt9.bind(remoteString) // GOOD
123+
stmt9.bind([remoteString]) // GOOD
124+
stmt9.bind(["username": remoteString]) // GOOD
125+
try stmt9.run(remoteString) // GOOD
126+
try stmt9.run([remoteString]) // GOOD
127+
try stmt9.run(["username": remoteString]) // GOOD
128+
try stmt9.scalar(remoteString) // GOOD
129+
try stmt9.scalar([remoteString]) // GOOD
130+
try stmt9.scalar(["username": remoteString]) // GOOD
131+
132+
Statement(db, remoteString).run() // BAD
133+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
edges
2+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:73:17:73:17 | unsafeQuery1 |
3+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:74:17:74:17 | unsafeQuery2 |
4+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:75:17:75:17 | unsafeQuery3 |
5+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:83:29:83:29 | unsafeQuery3 |
6+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:95:28:95:28 | remoteString |
7+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:100:29:100:29 | unsafeQuery1 |
8+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:103:29:103:29 | unsafeQuery1 |
9+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:106:29:106:29 | unsafeQuery1 |
10+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:109:9:109:9 | unsafeQuery1 |
11+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:111:9:111:9 | unsafeQuery1 |
12+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:113:9:113:9 | unsafeQuery1 |
13+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:115:12:115:12 | unsafeQuery1 |
14+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:117:12:117:12 | unsafeQuery1 |
15+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:119:12:119:12 | unsafeQuery1 |
16+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:132:16:132:16 | remoteString |
17+
| sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:133:33:133:33 | unsafeQuery1 |
18+
| sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:134:33:134:33 | unsafeQuery2 |
19+
| sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:135:33:135:33 | unsafeQuery3 |
20+
| sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:145:26:145:26 | unsafeQuery3 |
21+
| sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:175:29:175:29 | unsafeQuery3 |
22+
| sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:183:29:183:29 | unsafeQuery3 |
23+
nodes
24+
| SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | semmle.label | call to init(contentsOf:) : |
25+
| SQLite.swift:73:17:73:17 | unsafeQuery1 | semmle.label | unsafeQuery1 |
26+
| SQLite.swift:74:17:74:17 | unsafeQuery2 | semmle.label | unsafeQuery2 |
27+
| SQLite.swift:75:17:75:17 | unsafeQuery3 | semmle.label | unsafeQuery3 |
28+
| SQLite.swift:83:29:83:29 | unsafeQuery3 | semmle.label | unsafeQuery3 |
29+
| SQLite.swift:95:28:95:28 | remoteString | semmle.label | remoteString |
30+
| SQLite.swift:100:29:100:29 | unsafeQuery1 | semmle.label | unsafeQuery1 |
31+
| SQLite.swift:103:29:103:29 | unsafeQuery1 | semmle.label | unsafeQuery1 |
32+
| SQLite.swift:106:29:106:29 | unsafeQuery1 | semmle.label | unsafeQuery1 |
33+
| SQLite.swift:109:9:109:9 | unsafeQuery1 | semmle.label | unsafeQuery1 |
34+
| SQLite.swift:111:9:111:9 | unsafeQuery1 | semmle.label | unsafeQuery1 |
35+
| SQLite.swift:113:9:113:9 | unsafeQuery1 | semmle.label | unsafeQuery1 |
36+
| SQLite.swift:115:12:115:12 | unsafeQuery1 | semmle.label | unsafeQuery1 |
37+
| SQLite.swift:117:12:117:12 | unsafeQuery1 | semmle.label | unsafeQuery1 |
38+
| SQLite.swift:119:12:119:12 | unsafeQuery1 | semmle.label | unsafeQuery1 |
39+
| SQLite.swift:132:16:132:16 | remoteString | semmle.label | remoteString |
40+
| sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | semmle.label | call to init(contentsOf:) : |
41+
| sqlite3_c_api.swift:133:33:133:33 | unsafeQuery1 | semmle.label | unsafeQuery1 |
42+
| sqlite3_c_api.swift:134:33:134:33 | unsafeQuery2 | semmle.label | unsafeQuery2 |
43+
| sqlite3_c_api.swift:135:33:135:33 | unsafeQuery3 | semmle.label | unsafeQuery3 |
44+
| sqlite3_c_api.swift:145:26:145:26 | unsafeQuery3 | semmle.label | unsafeQuery3 |
45+
| sqlite3_c_api.swift:175:29:175:29 | unsafeQuery3 | semmle.label | unsafeQuery3 |
46+
| sqlite3_c_api.swift:183:29:183:29 | unsafeQuery3 | semmle.label | unsafeQuery3 |
47+
subpaths
48+
#select
49+
| SQLite.swift:73:17:73:17 | unsafeQuery1 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:73:17:73:17 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
50+
| SQLite.swift:74:17:74:17 | unsafeQuery2 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:74:17:74:17 | unsafeQuery2 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
51+
| SQLite.swift:75:17:75:17 | unsafeQuery3 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:75:17:75:17 | unsafeQuery3 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
52+
| SQLite.swift:83:29:83:29 | unsafeQuery3 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:83:29:83:29 | unsafeQuery3 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
53+
| SQLite.swift:95:28:95:28 | remoteString | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:95:28:95:28 | remoteString | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
54+
| SQLite.swift:100:29:100:29 | unsafeQuery1 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:100:29:100:29 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
55+
| SQLite.swift:103:29:103:29 | unsafeQuery1 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:103:29:103:29 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
56+
| SQLite.swift:106:29:106:29 | unsafeQuery1 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:106:29:106:29 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
57+
| SQLite.swift:109:9:109:9 | unsafeQuery1 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:109:9:109:9 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
58+
| SQLite.swift:111:9:111:9 | unsafeQuery1 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:111:9:111:9 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
59+
| SQLite.swift:113:9:113:9 | unsafeQuery1 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:113:9:113:9 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
60+
| SQLite.swift:115:12:115:12 | unsafeQuery1 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:115:12:115:12 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
61+
| SQLite.swift:117:12:117:12 | unsafeQuery1 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:117:12:117:12 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
62+
| SQLite.swift:119:12:119:12 | unsafeQuery1 | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:119:12:119:12 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
63+
| SQLite.swift:132:16:132:16 | remoteString | SQLite.swift:62:26:62:80 | call to init(contentsOf:) : | SQLite.swift:132:16:132:16 | remoteString | This query depends on a $@. | SQLite.swift:62:26:62:80 | call to init(contentsOf:) | user-provided value |
64+
| sqlite3_c_api.swift:133:33:133:33 | unsafeQuery1 | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:133:33:133:33 | unsafeQuery1 | This query depends on a $@. | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) | user-provided value |
65+
| sqlite3_c_api.swift:134:33:134:33 | unsafeQuery2 | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:134:33:134:33 | unsafeQuery2 | This query depends on a $@. | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) | user-provided value |
66+
| sqlite3_c_api.swift:135:33:135:33 | unsafeQuery3 | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:135:33:135:33 | unsafeQuery3 | This query depends on a $@. | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) | user-provided value |
67+
| sqlite3_c_api.swift:145:26:145:26 | unsafeQuery3 | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:145:26:145:26 | unsafeQuery3 | This query depends on a $@. | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) | user-provided value |
68+
| sqlite3_c_api.swift:175:29:175:29 | unsafeQuery3 | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:175:29:175:29 | unsafeQuery3 | This query depends on a $@. | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) | user-provided value |
69+
| sqlite3_c_api.swift:183:29:183:29 | unsafeQuery3 | sqlite3_c_api.swift:122:26:122:80 | call to init(contentsOf:) : | sqlite3_c_api.swift:183:29:183:29 | unsafeQuery3 | This query depends on a $@. | sqlite3_c_api.swift:122:26:122:80 | call to 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-089/SqlInjection.ql

0 commit comments

Comments
 (0)