Merge pull request #14312 from geoffw0/sqlpathinject2

Swift: Add sinks for sqlite3 and SQLite.swift to swift/cleartext-storage-database
This commit is contained in:
Robert Marsh
2023-10-05 14:08:55 -04:00
committed by GitHub
9 changed files with 579 additions and 2 deletions

View File

@@ -4,6 +4,7 @@
private import Alamofire.Alamofire
private import JavaScriptCore.JavaScriptCore
private import SQL.SQL
private import StandardLibrary.StandardLibrary
private import UIKit.UIKit
private import Xml.Xml

View File

@@ -0,0 +1,23 @@
/**
* Provides models for SQL libraries.
*/
import swift
private import codeql.swift.dataflow.ExternalFlow
/**
* A model for SQL library functions that permit taint flow.
*/
private class FilePathSummaries extends SummaryModelCsv {
override predicate row(string row) {
row =
[
// SQLite.Swift
";;false;<-(_:_:);;;Argument[0..1];ReturnValue;taint",
";Expression;true;init(_:_:);;;Argument[0];ReturnValue;taint",
";Expression;true;init(_:_:);;;Argument[1].CollectionElement;ReturnValue;taint",
";ExpressionType;true;init(_:);;;Argument[0];ReturnValue;taint",
";ExpressionType;true;replace(_:with:);;;Argument[1];ReturnValue;taint",
]
}
}

View File

@@ -108,7 +108,48 @@ private class CleartextStorageDatabaseSinks extends SinkModelCsv {
";FetchableRecord;true;fetchOne(_:arguments:adapter:);;;Argument[1];database-store",
";Statement;true;execute(arguments:);;;Argument[0];database-store",
";CommonTableExpression;true;init(recursive:named:columns:sql:arguments:);;;Argument[4];database-store",
";Statement;true;setArguments(_:);;;Argument[0];database-store"
";Statement;true;setArguments(_:);;;Argument[0];database-store",
// sqlite3 sinks
";;false;sqlite3_exec(_:_:_:_:_:);;;Argument[1];database-store",
";;false;sqlite3_prepare(_:_:_:_:_:);;;Argument[1];database-store",
";;false;sqlite3_prepare_v2(_:_:_:_:_:);;;Argument[1];database-store",
";;false;sqlite3_prepare_v3(_:_:_:_:_:_:);;;Argument[1];database-store",
";;false;sqlite3_prepare16(_:_:_:_:_:);;;Argument[1];database-store",
";;false;sqlite3_prepare16_v2(_:_:_:_:_:);;;Argument[1];database-store",
";;false;sqlite3_prepare16_v3(_:_:_:_:_:);;;Argument[1];database-store",
";;false;sqlite3_bind_blob(_:_:_:_:_:);;;Argument[2];database-store",
";;false;sqlite3_bind_blob64(_:_:_:_:_:);;;Argument[2];database-store",
";;false;sqlite3_bind_double(_:_:_:);;;Argument[2];database-store",
";;false;sqlite3_bind_int(_:_:_:);;;Argument[2];database-store",
";;false;sqlite3_bind_int64(_:_:_:);;;Argument[2];database-store",
";;false;sqlite3_bind_text(_:_:_:_:_:);;;Argument[2];database-store",
";;false;sqlite3_bind_text16(_:_:_:_:_:);;;Argument[2];database-store",
";;false;sqlite3_bind_text64(_:_:_:_:_:_:);;;Argument[2];database-store",
";;false;sqlite3_bind_value(_:_:_:);;;Argument[2];database-store",
";;false;sqlite3_bind_pointer(_:_:_:_:);;;Argument[2];database-store",
// SQLite.swift
";Connection;true;execute(_:);;;Argument[0];database-store",
";Connection;true;prepare(_:_:);;;Argument[0];database-store",
";Connection;true;prepare(_:_:);;;Argument[1];database-store",
";Connection;true;run(_:_:);;;Argument[0];database-store",
";Connection;true;run(_:_:);;;Argument[1];database-store",
";Connection;true;scalar(_:_:);;;Argument[0];database-store",
";Connection;true;scalar(_:_:);;;Argument[1];database-store",
";Statement;true;init(_:_:);;;Argument[1];database-store",
";Statement;true;bind(_:);;;Argument[0];database-store",
";Statement;true;run(_:);;;Argument[0];database-store",
";Statement;true;scalar(_:);;;Argument[0];database-store",
";QueryType;true;insert(_:);;;Argument[0];database-store",
";QueryType;true;insert(_:_:);;;Argument[0..1];database-store",
";QueryType;true;insert(or:_:);;;Argument[1];database-store",
";QueryType;true;insertMany(_:);;;Argument[0];database-store",
";QueryType;true;insertMany(or:_:);;;Argument[1];database-store",
";QueryType;true;upsert(_:onConflictOf:);;;Argument[0];database-store",
";QueryType;true;upsert(_:onConflictOf:setValues:);;;Argument[0];database-store",
";QueryType;true;upsert(_:onConflictOf:setValues:);;;Argument[2];database-store",
";QueryType;true;update(_:);;;Argument[0];database-store",
";QueryType;true;update(_:_:);;;Argument[0..1];database-store",
";QueryType;true;update(or:_:);;;Argument[1];database-store",
]
}
}

View File

@@ -40,7 +40,13 @@ module CleartextStorageDatabaseConfig implements DataFlow::ConfigSig {
c.getAReadContent().(DataFlow::Content::FieldContent).getField() = cx.getAMember()
)
or
// flow out from array elements of at the sink,
// flow out from dictionary tuple values at the sink (this is essential
// for some of the SQLite.swift models).
isSink(node) and
node.asExpr().getType().getUnderlyingType() instanceof DictionaryType and
c.getAReadContent().(DataFlow::Content::TupleContent).getIndex() = 1
or
// flow out from array elements (and other collection content) at the sink,
// for example in `database.allStatements(sql: "", arguments: [sensitive])`.
isSink(node) and
c.getAReadContent() instanceof DataFlow::Content::CollectionContent

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added sqlite3 and SQLite.swift sinks and flow summaries for the `swift/cleartext-storage-database` query.

View File

@@ -1,4 +1,74 @@
edges
| SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:123:17:123:17 | insertQuery |
| SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:127:21:127:21 | insertQuery |
| SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:131:17:131:17 | insertQuery |
| SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:135:20:135:20 | insertQuery |
| SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:139:24:139:24 | insertQuery |
| SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:124:17:124:17 | updateQuery |
| SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:128:21:128:21 | updateQuery |
| SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:132:17:132:17 | updateQuery |
| SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:136:20:136:20 | updateQuery |
| SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:140:24:140:24 | updateQuery |
| SQLite.swift:147:32:147:32 | [...] [Collection element] | SQLite.swift:147:32:147:32 | [...] |
| SQLite.swift:147:32:147:32 | mobilePhoneNumber | SQLite.swift:147:32:147:32 | [...] [Collection element] |
| SQLite.swift:148:28:148:28 | [...] [Collection element] | SQLite.swift:148:28:148:28 | [...] |
| SQLite.swift:148:28:148:28 | mobilePhoneNumber | SQLite.swift:148:28:148:28 | [...] [Collection element] |
| SQLite.swift:149:31:149:31 | [...] [Collection element] | SQLite.swift:149:31:149:31 | [...] |
| SQLite.swift:149:31:149:31 | mobilePhoneNumber | SQLite.swift:149:31:149:31 | [...] [Collection element] |
| SQLite.swift:152:21:152:21 | [...] [Collection element] | SQLite.swift:152:21:152:21 | [...] |
| SQLite.swift:152:21:152:21 | mobilePhoneNumber | SQLite.swift:152:21:152:21 | [...] [Collection element] |
| SQLite.swift:153:20:153:20 | [...] [Collection element] | SQLite.swift:153:20:153:20 | [...] |
| SQLite.swift:153:20:153:20 | mobilePhoneNumber | SQLite.swift:153:20:153:20 | [...] [Collection element] |
| SQLite.swift:154:23:154:23 | [...] [Collection element] | SQLite.swift:154:23:154:23 | [...] |
| SQLite.swift:154:23:154:23 | mobilePhoneNumber | SQLite.swift:154:23:154:23 | [...] [Collection element] |
| SQLite.swift:158:32:158:54 | [...] [Collection element] | SQLite.swift:158:32:158:54 | [...] |
| SQLite.swift:158:33:158:33 | mobilePhoneNumber | SQLite.swift:158:32:158:54 | [...] [Collection element] |
| SQLite.swift:159:28:159:50 | [...] [Collection element] | SQLite.swift:159:28:159:50 | [...] |
| SQLite.swift:159:29:159:29 | mobilePhoneNumber | SQLite.swift:159:28:159:50 | [...] [Collection element] |
| SQLite.swift:160:31:160:53 | [...] [Collection element] | SQLite.swift:160:31:160:53 | [...] |
| SQLite.swift:160:32:160:32 | mobilePhoneNumber | SQLite.swift:160:31:160:53 | [...] [Collection element] |
| SQLite.swift:163:21:163:43 | [...] [Collection element] | SQLite.swift:163:21:163:43 | [...] |
| SQLite.swift:163:22:163:22 | mobilePhoneNumber | SQLite.swift:163:21:163:43 | [...] [Collection element] |
| SQLite.swift:164:20:164:42 | [...] [Collection element] | SQLite.swift:164:20:164:42 | [...] |
| SQLite.swift:164:21:164:21 | mobilePhoneNumber | SQLite.swift:164:20:164:42 | [...] [Collection element] |
| SQLite.swift:165:23:165:45 | [...] [Collection element] | SQLite.swift:165:23:165:45 | [...] |
| SQLite.swift:165:24:165:24 | mobilePhoneNumber | SQLite.swift:165:23:165:45 | [...] [Collection element] |
| SQLite.swift:169:32:169:70 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:169:32:169:70 | [...] |
| SQLite.swift:169:43:169:53 | (...) [Tuple element at index 1] | SQLite.swift:169:32:169:70 | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:169:53:169:53 | mobilePhoneNumber | SQLite.swift:169:43:169:53 | (...) [Tuple element at index 1] |
| SQLite.swift:170:28:170:66 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:170:28:170:66 | [...] |
| SQLite.swift:170:39:170:49 | (...) [Tuple element at index 1] | SQLite.swift:170:28:170:66 | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:170:49:170:49 | mobilePhoneNumber | SQLite.swift:170:39:170:49 | (...) [Tuple element at index 1] |
| SQLite.swift:171:31:171:69 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:171:31:171:69 | [...] |
| SQLite.swift:171:42:171:52 | (...) [Tuple element at index 1] | SQLite.swift:171:31:171:69 | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:171:52:171:52 | mobilePhoneNumber | SQLite.swift:171:42:171:52 | (...) [Tuple element at index 1] |
| SQLite.swift:174:21:174:59 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:174:21:174:59 | [...] |
| SQLite.swift:174:32:174:42 | (...) [Tuple element at index 1] | SQLite.swift:174:21:174:59 | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:174:42:174:42 | mobilePhoneNumber | SQLite.swift:174:32:174:42 | (...) [Tuple element at index 1] |
| SQLite.swift:175:20:175:58 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:175:20:175:58 | [...] |
| SQLite.swift:175:31:175:41 | (...) [Tuple element at index 1] | SQLite.swift:175:20:175:58 | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:175:41:175:41 | mobilePhoneNumber | SQLite.swift:175:31:175:41 | (...) [Tuple element at index 1] |
| SQLite.swift:176:23:176:61 | [...] [Collection element, Tuple element at index 1] | SQLite.swift:176:23:176:61 | [...] |
| SQLite.swift:176:34:176:44 | (...) [Tuple element at index 1] | SQLite.swift:176:23:176:61 | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:176:44:176:44 | mobilePhoneNumber | SQLite.swift:176:34:176:44 | (...) [Tuple element at index 1] |
| SQLite.swift:186:40:186:54 | ... <-(_:_:) ... | SQLite.swift:186:40:186:54 | [...] [Collection element] |
| SQLite.swift:186:40:186:54 | [...] [Collection element] | SQLite.swift:186:40:186:54 | [...] |
| SQLite.swift:186:54:186:54 | mobilePhoneNumber | SQLite.swift:186:40:186:54 | ... <-(_:_:) ... |
| SQLite.swift:189:26:189:40 | ... <-(_:_:) ... | SQLite.swift:189:26:189:40 | [...] [Collection element] |
| SQLite.swift:189:26:189:40 | [...] [Collection element] | SQLite.swift:189:26:189:40 | [...] |
| SQLite.swift:189:40:189:40 | mobilePhoneNumber | SQLite.swift:189:26:189:40 | ... <-(_:_:) ... |
| SQLite.swift:191:27:191:41 | ... <-(_:_:) ... | SQLite.swift:191:27:191:41 | [...] [Collection element] |
| SQLite.swift:191:27:191:41 | [...] [Collection element] | SQLite.swift:191:27:191:41 | [...] |
| SQLite.swift:191:41:191:41 | mobilePhoneNumber | SQLite.swift:191:27:191:41 | ... <-(_:_:) ... |
| SQLite.swift:193:26:193:89 | ... <-(_:_:) ... | SQLite.swift:193:26:193:89 | [...] [Collection element] |
| SQLite.swift:193:26:193:89 | [...] [Collection element] | SQLite.swift:193:26:193:89 | [...] |
| SQLite.swift:193:40:193:89 | call to replace(_:with:) | SQLite.swift:193:26:193:89 | ... <-(_:_:) ... |
| SQLite.swift:193:72:193:72 | mobilePhoneNumber | SQLite.swift:193:40:193:89 | call to replace(_:with:) |
| SQLite.swift:197:16:197:50 | [...] [Collection element, Collection element] | SQLite.swift:199:30:199:30 | badMany |
| SQLite.swift:197:16:197:50 | [...] [Collection element, Collection element] | SQLite.swift:201:54:201:54 | badMany |
| SQLite.swift:197:17:197:49 | [...] [Collection element] | SQLite.swift:197:16:197:50 | [...] [Collection element, Collection element] |
| SQLite.swift:197:18:197:32 | ... <-(_:_:) ... | SQLite.swift:197:17:197:49 | [...] [Collection element] |
| SQLite.swift:197:32:197:32 | mobilePhoneNumber | SQLite.swift:197:18:197:32 | ... <-(_:_:) ... |
| file://:0:0:0:0 | self | file://:0:0:0:0 | .value |
| file://:0:0:0:0 | self | file://:0:0:0:0 | .value2 |
| file://:0:0:0:0 | self [value] | file://:0:0:0:0 | .value |
@@ -6,6 +76,8 @@ edges
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] |
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [password] |
| file://:0:0:0:0 | value | file://:0:0:0:0 | [post] self [value] |
| sqlite3_c_api.swift:42:69:42:69 | medicalNotes | sqlite3_c_api.swift:46:27:46:27 | insertQuery |
| sqlite3_c_api.swift:43:49:43:49 | medicalNotes | sqlite3_c_api.swift:47:27:47:27 | updateQuery |
| testCoreData2.swift:23:13:23:13 | value | file://:0:0:0:0 | value |
| testCoreData2.swift:37:2:37:2 | [post] obj [myValue] | testCoreData2.swift:37:2:37:2 | [post] obj |
| testCoreData2.swift:37:16:37:16 | bankAccountNo | testCoreData2.swift:37:2:37:2 | [post] obj [myValue] |
@@ -234,6 +306,101 @@ edges
| testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:34:6:34:6 | value |
| testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:73:2:73:2 | [post] h [password] |
nodes
| SQLite.swift:119:70:119:70 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:120:50:120:50 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:123:17:123:17 | insertQuery | semmle.label | insertQuery |
| SQLite.swift:124:17:124:17 | updateQuery | semmle.label | updateQuery |
| SQLite.swift:127:21:127:21 | insertQuery | semmle.label | insertQuery |
| SQLite.swift:128:21:128:21 | updateQuery | semmle.label | updateQuery |
| SQLite.swift:131:17:131:17 | insertQuery | semmle.label | insertQuery |
| SQLite.swift:132:17:132:17 | updateQuery | semmle.label | updateQuery |
| SQLite.swift:135:20:135:20 | insertQuery | semmle.label | insertQuery |
| SQLite.swift:136:20:136:20 | updateQuery | semmle.label | updateQuery |
| SQLite.swift:139:24:139:24 | insertQuery | semmle.label | insertQuery |
| SQLite.swift:140:24:140:24 | updateQuery | semmle.label | updateQuery |
| SQLite.swift:147:32:147:32 | [...] | semmle.label | [...] |
| SQLite.swift:147:32:147:32 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:147:32:147:32 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:148:28:148:28 | [...] | semmle.label | [...] |
| SQLite.swift:148:28:148:28 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:148:28:148:28 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:149:31:149:31 | [...] | semmle.label | [...] |
| SQLite.swift:149:31:149:31 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:149:31:149:31 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:152:21:152:21 | [...] | semmle.label | [...] |
| SQLite.swift:152:21:152:21 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:152:21:152:21 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:153:20:153:20 | [...] | semmle.label | [...] |
| SQLite.swift:153:20:153:20 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:153:20:153:20 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:154:23:154:23 | [...] | semmle.label | [...] |
| SQLite.swift:154:23:154:23 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:154:23:154:23 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:158:32:158:54 | [...] | semmle.label | [...] |
| SQLite.swift:158:32:158:54 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:158:33:158:33 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:159:28:159:50 | [...] | semmle.label | [...] |
| SQLite.swift:159:28:159:50 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:159:29:159:29 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:160:31:160:53 | [...] | semmle.label | [...] |
| SQLite.swift:160:31:160:53 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:160:32:160:32 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:163:21:163:43 | [...] | semmle.label | [...] |
| SQLite.swift:163:21:163:43 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:163:22:163:22 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:164:20:164:42 | [...] | semmle.label | [...] |
| SQLite.swift:164:20:164:42 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:164:21:164:21 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:165:23:165:45 | [...] | semmle.label | [...] |
| SQLite.swift:165:23:165:45 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:165:24:165:24 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:169:32:169:70 | [...] | semmle.label | [...] |
| SQLite.swift:169:32:169:70 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:169:43:169:53 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] |
| SQLite.swift:169:53:169:53 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:170:28:170:66 | [...] | semmle.label | [...] |
| SQLite.swift:170:28:170:66 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:170:39:170:49 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] |
| SQLite.swift:170:49:170:49 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:171:31:171:69 | [...] | semmle.label | [...] |
| SQLite.swift:171:31:171:69 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:171:42:171:52 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] |
| SQLite.swift:171:52:171:52 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:174:21:174:59 | [...] | semmle.label | [...] |
| SQLite.swift:174:21:174:59 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:174:32:174:42 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] |
| SQLite.swift:174:42:174:42 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:175:20:175:58 | [...] | semmle.label | [...] |
| SQLite.swift:175:20:175:58 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:175:31:175:41 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] |
| SQLite.swift:175:41:175:41 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:176:23:176:61 | [...] | semmle.label | [...] |
| SQLite.swift:176:23:176:61 | [...] [Collection element, Tuple element at index 1] | semmle.label | [...] [Collection element, Tuple element at index 1] |
| SQLite.swift:176:34:176:44 | (...) [Tuple element at index 1] | semmle.label | (...) [Tuple element at index 1] |
| SQLite.swift:176:44:176:44 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:186:40:186:54 | ... <-(_:_:) ... | semmle.label | ... <-(_:_:) ... |
| SQLite.swift:186:40:186:54 | [...] | semmle.label | [...] |
| SQLite.swift:186:40:186:54 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:186:54:186:54 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:189:26:189:40 | ... <-(_:_:) ... | semmle.label | ... <-(_:_:) ... |
| SQLite.swift:189:26:189:40 | [...] | semmle.label | [...] |
| SQLite.swift:189:26:189:40 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:189:40:189:40 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:191:27:191:41 | ... <-(_:_:) ... | semmle.label | ... <-(_:_:) ... |
| SQLite.swift:191:27:191:41 | [...] | semmle.label | [...] |
| SQLite.swift:191:27:191:41 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:191:41:191:41 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:193:26:193:89 | ... <-(_:_:) ... | semmle.label | ... <-(_:_:) ... |
| SQLite.swift:193:26:193:89 | [...] | semmle.label | [...] |
| SQLite.swift:193:26:193:89 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:193:40:193:89 | call to replace(_:with:) | semmle.label | call to replace(_:with:) |
| SQLite.swift:193:72:193:72 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:197:16:197:50 | [...] [Collection element, Collection element] | semmle.label | [...] [Collection element, Collection element] |
| SQLite.swift:197:17:197:49 | [...] [Collection element] | semmle.label | [...] [Collection element] |
| SQLite.swift:197:18:197:32 | ... <-(_:_:) ... | semmle.label | ... <-(_:_:) ... |
| SQLite.swift:197:32:197:32 | mobilePhoneNumber | semmle.label | mobilePhoneNumber |
| SQLite.swift:199:30:199:30 | badMany | semmle.label | badMany |
| SQLite.swift:201:54:201:54 | badMany | semmle.label | badMany |
| file://:0:0:0:0 | .value | semmle.label | .value |
| file://:0:0:0:0 | .value | semmle.label | .value |
| file://:0:0:0:0 | .value2 | semmle.label | .value2 |
@@ -248,6 +415,11 @@ nodes
| file://:0:0:0:0 | value | semmle.label | value |
| file://:0:0:0:0 | value | semmle.label | value |
| file://:0:0:0:0 | value | semmle.label | value |
| sqlite3_c_api.swift:42:69:42:69 | medicalNotes | semmle.label | medicalNotes |
| sqlite3_c_api.swift:43:49:43:49 | medicalNotes | semmle.label | medicalNotes |
| sqlite3_c_api.swift:46:27:46:27 | insertQuery | semmle.label | insertQuery |
| sqlite3_c_api.swift:47:27:47:27 | updateQuery | semmle.label | updateQuery |
| sqlite3_c_api.swift:58:36:58:36 | medicalNotes | semmle.label | medicalNotes |
| testCoreData2.swift:23:13:23:13 | value | semmle.label | value |
| testCoreData2.swift:37:2:37:2 | [post] obj | semmle.label | [post] obj |
| testCoreData2.swift:37:2:37:2 | [post] obj [myValue] | semmle.label | [post] obj [myValue] |
@@ -567,6 +739,43 @@ subpaths
| testRealm.swift:66:11:66:11 | myPassword | testRealm.swift:27:6:27:6 | value | file://:0:0:0:0 | [post] self [data] | testRealm.swift:66:2:66:2 | [post] g [data] |
| testRealm.swift:73:15:73:15 | myPassword | testRealm.swift:34:6:34:6 | value | file://:0:0:0:0 | [post] self [password] | testRealm.swift:73:2:73:2 | [post] h [password] |
#select
| SQLite.swift:123:17:123:17 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:123:17:123:17 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:124:17:124:17 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:124:17:124:17 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:127:21:127:21 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:127:21:127:21 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:128:21:128:21 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:128:21:128:21 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:131:17:131:17 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:131:17:131:17 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:132:17:132:17 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:132:17:132:17 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:135:20:135:20 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:135:20:135:20 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:136:20:136:20 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:136:20:136:20 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:139:24:139:24 | insertQuery | SQLite.swift:119:70:119:70 | mobilePhoneNumber | SQLite.swift:139:24:139:24 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:119:70:119:70 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:140:24:140:24 | updateQuery | SQLite.swift:120:50:120:50 | mobilePhoneNumber | SQLite.swift:140:24:140:24 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:120:50:120:50 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:147:32:147:32 | [...] | SQLite.swift:147:32:147:32 | mobilePhoneNumber | SQLite.swift:147:32:147:32 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:147:32:147:32 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:148:28:148:28 | [...] | SQLite.swift:148:28:148:28 | mobilePhoneNumber | SQLite.swift:148:28:148:28 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:148:28:148:28 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:149:31:149:31 | [...] | SQLite.swift:149:31:149:31 | mobilePhoneNumber | SQLite.swift:149:31:149:31 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:149:31:149:31 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:152:21:152:21 | [...] | SQLite.swift:152:21:152:21 | mobilePhoneNumber | SQLite.swift:152:21:152:21 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:152:21:152:21 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:153:20:153:20 | [...] | SQLite.swift:153:20:153:20 | mobilePhoneNumber | SQLite.swift:153:20:153:20 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:153:20:153:20 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:154:23:154:23 | [...] | SQLite.swift:154:23:154:23 | mobilePhoneNumber | SQLite.swift:154:23:154:23 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:154:23:154:23 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:158:32:158:54 | [...] | SQLite.swift:158:33:158:33 | mobilePhoneNumber | SQLite.swift:158:32:158:54 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:158:33:158:33 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:159:28:159:50 | [...] | SQLite.swift:159:29:159:29 | mobilePhoneNumber | SQLite.swift:159:28:159:50 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:159:29:159:29 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:160:31:160:53 | [...] | SQLite.swift:160:32:160:32 | mobilePhoneNumber | SQLite.swift:160:31:160:53 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:160:32:160:32 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:163:21:163:43 | [...] | SQLite.swift:163:22:163:22 | mobilePhoneNumber | SQLite.swift:163:21:163:43 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:163:22:163:22 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:164:20:164:42 | [...] | SQLite.swift:164:21:164:21 | mobilePhoneNumber | SQLite.swift:164:20:164:42 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:164:21:164:21 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:165:23:165:45 | [...] | SQLite.swift:165:24:165:24 | mobilePhoneNumber | SQLite.swift:165:23:165:45 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:165:24:165:24 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:169:32:169:70 | [...] | SQLite.swift:169:53:169:53 | mobilePhoneNumber | SQLite.swift:169:32:169:70 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:169:53:169:53 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:170:28:170:66 | [...] | SQLite.swift:170:49:170:49 | mobilePhoneNumber | SQLite.swift:170:28:170:66 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:170:49:170:49 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:171:31:171:69 | [...] | SQLite.swift:171:52:171:52 | mobilePhoneNumber | SQLite.swift:171:31:171:69 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:171:52:171:52 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:174:21:174:59 | [...] | SQLite.swift:174:42:174:42 | mobilePhoneNumber | SQLite.swift:174:21:174:59 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:174:42:174:42 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:175:20:175:58 | [...] | SQLite.swift:175:41:175:41 | mobilePhoneNumber | SQLite.swift:175:20:175:58 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:175:41:175:41 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:176:23:176:61 | [...] | SQLite.swift:176:44:176:44 | mobilePhoneNumber | SQLite.swift:176:23:176:61 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:176:44:176:44 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:186:40:186:54 | [...] | SQLite.swift:186:54:186:54 | mobilePhoneNumber | SQLite.swift:186:40:186:54 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:186:54:186:54 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:189:26:189:40 | [...] | SQLite.swift:189:40:189:40 | mobilePhoneNumber | SQLite.swift:189:26:189:40 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:189:40:189:40 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:191:27:191:41 | [...] | SQLite.swift:191:41:191:41 | mobilePhoneNumber | SQLite.swift:191:27:191:41 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:191:41:191:41 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:193:26:193:89 | [...] | SQLite.swift:193:72:193:72 | mobilePhoneNumber | SQLite.swift:193:26:193:89 | [...] | This operation stores '[...]' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:193:72:193:72 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:199:30:199:30 | badMany | SQLite.swift:197:32:197:32 | mobilePhoneNumber | SQLite.swift:199:30:199:30 | badMany | This operation stores 'badMany' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:197:32:197:32 | mobilePhoneNumber | mobilePhoneNumber |
| SQLite.swift:201:54:201:54 | badMany | SQLite.swift:197:32:197:32 | mobilePhoneNumber | SQLite.swift:201:54:201:54 | badMany | This operation stores 'badMany' in a database. It may contain unencrypted sensitive data from $@. | SQLite.swift:197:32:197:32 | mobilePhoneNumber | mobilePhoneNumber |
| sqlite3_c_api.swift:46:27:46:27 | insertQuery | sqlite3_c_api.swift:42:69:42:69 | medicalNotes | sqlite3_c_api.swift:46:27:46:27 | insertQuery | This operation stores 'insertQuery' in a database. It may contain unencrypted sensitive data from $@. | sqlite3_c_api.swift:42:69:42:69 | medicalNotes | medicalNotes |
| sqlite3_c_api.swift:47:27:47:27 | updateQuery | sqlite3_c_api.swift:43:49:43:49 | medicalNotes | sqlite3_c_api.swift:47:27:47:27 | updateQuery | This operation stores 'updateQuery' in a database. It may contain unencrypted sensitive data from $@. | sqlite3_c_api.swift:43:49:43:49 | medicalNotes | medicalNotes |
| sqlite3_c_api.swift:58:36:58:36 | medicalNotes | sqlite3_c_api.swift:58:36:58:36 | medicalNotes | sqlite3_c_api.swift:58:36:58:36 | medicalNotes | This operation stores 'medicalNotes' in a database. It may contain unencrypted sensitive data from $@. | sqlite3_c_api.swift:58:36:58:36 | medicalNotes | medicalNotes |
| testCoreData2.swift:37:2:37:2 | obj | testCoreData2.swift:37:16:37:16 | bankAccountNo | testCoreData2.swift:37:2:37:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:37:16:37:16 | bankAccountNo | bankAccountNo |
| testCoreData2.swift:39:2:39:2 | obj | testCoreData2.swift:39:28:39:28 | bankAccountNo | testCoreData2.swift:39:2:39:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:39:28:39:28 | bankAccountNo | bankAccountNo |
| testCoreData2.swift:41:2:41:2 | obj | testCoreData2.swift:41:29:41:29 | bankAccountNo | testCoreData2.swift:41:2:41:2 | [post] obj | This operation stores 'obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:41:29:41:29 | bankAccountNo | bankAccountNo |

View File

@@ -0,0 +1,202 @@
// --- stubs ---
public protocol Binding {}
public protocol Number: Binding {}
extension String: Binding {}
extension Int: Number {}
class Statement {
fileprivate let connection: Connection
init(_ connection: Connection, _ SQL: String) throws { self.connection = connection}
public func bind(_ values: Binding?...) -> Statement { return self }
public func bind(_ values: [Binding?]) -> Statement { return self }
public func bind(_ values: [String: Binding?]) -> Statement { return self }
@discardableResult public func run(_ bindings: Binding?...) throws -> Statement { return self }
@discardableResult public func run(_ bindings: [Binding?]) throws -> Statement { return self }
@discardableResult public func run(_ bindings: [String: Binding?]) throws -> Statement { return self }
public func scalar(_ bindings: Binding?...) throws -> Binding? { return nil }
public func scalar(_ bindings: [Binding?]) throws -> Binding? { return nil }
public func scalar(_ bindings: [String: Binding?]) throws -> Binding? { return nil }
}
class Connection {
public func execute(_ SQL: String) throws { }
public func prepare(_ statement: String, _ bindings: Binding?...) throws -> Statement { return try Statement(self, "") }
public func prepare(_ statement: String, _ bindings: [Binding?]) throws -> Statement { return try Statement(self, "") }
public func prepare(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement { return try Statement(self, "") }
@discardableResult public func run(_ statement: String, _ bindings: Binding?...) throws -> Statement { return try Statement(self, "") }
@discardableResult public func run(_ statement: String, _ bindings: [Binding?]) throws -> Statement { return try Statement(self, "") }
@discardableResult public func run(_ statement: String, _ bindings: [String: Binding?]) throws -> Statement { return try Statement(self, "") }
public func scalar(_ statement: String, _ bindings: Binding?...) throws -> Binding? { return nil }
public func scalar(_ statement: String, _ bindings: [Binding?]) throws -> Binding? { return nil }
public func scalar(_ statement: String, _ bindings: [String: Binding?]) throws -> Binding? { return nil }
}
protocol QueryType { }
protocol SchemaType: QueryType { }
struct Table: SchemaType {
init(_ name: String, database: String? = nil) { }
}
protocol ExpressionType : CustomStringConvertible {
init(_ template: String, _ bindings: [Binding?])
}
extension ExpressionType {
init(_ identifier: String) {
self.init(identifier, [])
}
var description: String { get { "" } }
}
extension ExpressionType { // where UnderlyingType == String
public func replace(_ pattern: String, with replacement: String) -> Expression<String> {
return Expression<String>("")
}
}
struct Expression<Datatype> : ExpressionType {
typealias UnderlyingType = Datatype
init(_ template: String, _ bindings: [Binding?]) { }
}
struct Insert: ExpressionType {
init(_ template: String, _ bindings: [Binding?]) { }
}
struct Update: ExpressionType {
init(_ template: String, _ bindings: [Binding?]) { }
}
extension Connection {
@discardableResult public func run(_ query: Insert) throws -> Int64 { return 0 }
@discardableResult public func run(_ query: Update) throws -> Int { return 0 }
}
struct Setter { }
infix operator <-
func <-<V>(column: Expression<V>, value: Expression<V>) -> Setter { return Setter() }
func <-<V>(column: Expression<V>, value: V) -> Setter { return Setter() }
enum OnConflict: String {
case replace = "REPLACE"
}
extension QueryType {
func filter(_ predicate: Expression<Bool>) -> Self { return self }
func insert(_ value: Setter, _ more: Setter...) -> Insert { return Insert("") }
func insertMany(_ values: [[Setter]]) -> Insert { return Insert("") }
func insertMany(or onConflict: OnConflict, _ values: [[Setter]]) -> Insert { return Insert("") }
func update(_ values: Setter...) -> Update { return Update("") }
}
func ==<V>(lhs: Expression<V>, rhs: V) -> Expression<Bool> { return Expression<Bool>("") }
// --- tests ---
func test_sqlite_swift_api(db: Connection, id: Int, mobilePhoneNumber: String) throws {
// --- sensitive data in SQL (in practice these cases may also be SQL injection) ---
let insertQuery = "INSERT INTO CONTACTS(ID, NUMBER) VALUES(\(id), \(mobilePhoneNumber));"
let updateQuery = "UPDATE CONTACTS SET NUMBER=\(mobilePhoneNumber) WHERE ID=\(id);"
let deleteQuery = "DELETE FROM CONTACTS WHERE ID=\(id);"
try db.execute(insertQuery) // BAD (sensitive data)
try db.execute(updateQuery) // BAD (sensitive data)
try db.execute(deleteQuery) // GOOD
_ = try db.prepare(insertQuery).run() // BAD (sensitive data)
_ = try db.prepare(updateQuery).run() // BAD (sensitive data)
_ = try db.prepare(deleteQuery).run() // GOOD
_ = try db.run(insertQuery) // BAD (sensitive data)
_ = try db.run(updateQuery) // BAD (sensitive data)
_ = try db.run(deleteQuery) // GOOD
_ = try db.scalar(insertQuery) // BAD (sensitive data)
_ = try db.scalar(updateQuery) // BAD (sensitive data)
_ = try db.scalar(deleteQuery) // GOOD
_ = try Statement(db, insertQuery).run() // BAD (sensitive data)
_ = try Statement(db, updateQuery).run() // BAD (sensitive data)
_ = try Statement(db, deleteQuery).run() // GOOD
// --- sensitive data in bindings ---
let varQuery1 = "UPDATE CONTACTS SET NUMBER=?;"
_ = try db.prepare(varQuery1, mobilePhoneNumber).run() // BAD (sensitive data)
_ = try db.run(varQuery1, mobilePhoneNumber) // BAD (sensitive data)
_ = try db.scalar(varQuery1, mobilePhoneNumber) // BAD (sensitive data)
let stmt1 = try db.prepare(varQuery1) // GOOD
_ = try stmt1.bind(mobilePhoneNumber).run() // BAD (sensitive data)
_ = try stmt1.run(mobilePhoneNumber) // BAD (sensitive data)
_ = try stmt1.scalar(mobilePhoneNumber) // BAD (sensitive data)
let varQuery2 = "UPDATE CONTACTS SET NUMBER=? WHERE ID=?;"
_ = try db.prepare(varQuery2, [mobilePhoneNumber, id]).run() // BAD (sensitive data)
_ = try db.run(varQuery2, [mobilePhoneNumber, id]) // BAD (sensitive data)
_ = try db.scalar(varQuery2, [mobilePhoneNumber, id]) // BAD (sensitive data)
let stmt2 = try db.prepare(varQuery2) // GOOD
_ = try stmt2.bind([mobilePhoneNumber, id]).run() // BAD (sensitive data)
_ = try stmt2.run([mobilePhoneNumber, id]) // BAD (sensitive data)
_ = try stmt2.scalar([mobilePhoneNumber, id]) // BAD (sensitive data)
let varQuery3 = "UPDATE CONTACTS SET NUMBER=$number WHERE ID=$id;"
_ = try db.prepare(varQuery3, ["id": id, "number": mobilePhoneNumber]).run() // BAD (sensitive data)
_ = try db.run(varQuery3, ["id": id, "number": mobilePhoneNumber]) // BAD (sensitive data)
_ = try db.scalar(varQuery3, ["id": id, "number": mobilePhoneNumber]) // BAD (sensitive data)
let stmt3 = try db.prepare(varQuery3) // GOOD
_ = try stmt3.bind(["id": id, "number": mobilePhoneNumber]).run() // BAD (sensitive data)
_ = try stmt3.run(["id": id, "number": mobilePhoneNumber]) // BAD (sensitive data)
_ = try stmt3.scalar(["id": id, "number": mobilePhoneNumber]) // BAD (sensitive data)
// --- higher level insert / update ---
let table = Table("TABLE")
let idExpr = Expression<Int>("ID")
let numberExpr = Expression<String>("NUMBER")
let filter = table.filter(idExpr == id) // GOOD
try db.run(table.insert(idExpr <- id, numberExpr <- "123")) // GOOD
try db.run(table.insert(idExpr <- id, numberExpr <- mobilePhoneNumber)) // BAD (sensitive data)
try db.run(table.update(numberExpr <- "123")) // GOOD
try db.run(table.update(numberExpr <- mobilePhoneNumber)) // BAD (sensitive data)
try db.run(filter.update(numberExpr <- "123")) // GOOD
try db.run(filter.update(numberExpr <- mobilePhoneNumber)) // BAD (sensitive data)
try db.run(table.update(numberExpr <- numberExpr.replace("123", with: "456"))) // GOOD
try db.run(table.update(numberExpr <- numberExpr.replace("123", with: mobilePhoneNumber))) // BAD (sensitive data)
// (much more complex query construction is possible in SQLite.swift)
let goodMany = [[numberExpr <- "456"]]
let badMany = [[numberExpr <- mobilePhoneNumber]]
try db.run(table.insertMany(goodMany)) // GOOD
try db.run(table.insertMany(badMany)) // BAD (sensitive data)
try db.run(table.insertMany(or: OnConflict.replace, goodMany)) // GOOD
try db.run(table.insertMany(or: OnConflict.replace, badMany)) // BAD (sensitive data)
}

View File

@@ -1,3 +1,31 @@
| SQLite.swift:119:70:119:70 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:120:50:120:50 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:147:32:147:32 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:148:28:148:28 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:149:31:149:31 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:152:21:152:21 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:153:20:153:20 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:154:23:154:23 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:158:33:158:33 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:159:29:159:29 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:160:32:160:32 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:163:22:163:22 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:164:21:164:21 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:165:24:165:24 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:169:53:169:53 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:170:49:170:49 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:171:52:171:52 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:174:42:174:42 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:175:41:175:41 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:176:44:176:44 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:186:54:186:54 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:189:40:189:40 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:191:41:191:41 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:193:72:193:72 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| SQLite.swift:197:32:197:32 | mobilePhoneNumber | label:mobilePhoneNumber, type:private information |
| sqlite3_c_api.swift:42:69:42:69 | medicalNotes | label:medicalNotes, type:private information |
| sqlite3_c_api.swift:43:49:43:49 | medicalNotes | label:medicalNotes, type:private information |
| sqlite3_c_api.swift:58:36:58:36 | medicalNotes | label:medicalNotes, type:private information |
| testAlamofire.swift:150:45:150:45 | password | label:password, type:credential |
| testAlamofire.swift:152:51:152:51 | password | label:password, type:credential |
| testAlamofire.swift:154:38:154:38 | email | label:email, type:private information |

View File

@@ -0,0 +1,63 @@
// --- stubs ---
var SQLITE_OK : Int32 = 0
var SQLITE_TRANSIENT : (@convention(c) (UnsafeMutableRawPointer?) -> Void)?
func sqlite3_exec(
_ _: OpaquePointer?,
_ sql: UnsafePointer<CChar>?,
_ callback: (@convention(c) (UnsafeMutableRawPointer?, Int32, UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?, UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?) -> Int32)?,
_ _: UnsafeMutableRawPointer?,
_ errmsg: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>?
) -> Int32 { return SQLITE_OK }
func sqlite3_prepare(
_ db: OpaquePointer?,
_ zSql: UnsafePointer<CChar>?,
_ nByte: Int32,
_ ppStmt: UnsafeMutablePointer<OpaquePointer?>?,
_ pzTail: UnsafeMutablePointer<UnsafePointer<CChar>?>?
) -> Int32 { return SQLITE_OK }
func sqlite3_bind_int(
_ _: OpaquePointer?,
_ _: Int32,
_ _: Int32
) -> Int32 { return SQLITE_OK }
func sqlite3_bind_text(
_ _: OpaquePointer?,
_ _: Int32,
_ _: UnsafePointer<CChar>?,
_ _: Int32,
_ callback: (@convention(c) (UnsafeMutableRawPointer?) -> Void)?
) -> Int32 { return SQLITE_OK }
// --- tests ---
func test_sqlite3_c_api(db: OpaquePointer?, id: Int32, medicalNotes: String) {
// --- sensitive data in SQL (in practice these cases may also be SQL injection) ---
let insertQuery = "INSERT INTO PATIENTS(ID, NOTES) VALUES(\(id), \(medicalNotes));"
let updateQuery = "UPDATE PATIENTS SET NOTES=\(medicalNotes) WHERE ID=\(id);"
let deleteQuery = "DELETE FROM PATIENTS WHERE ID=\(id);"
let _ = sqlite3_exec(db, insertQuery, nil, nil, nil) // BAD (sensitive data)
let _ = sqlite3_exec(db, updateQuery, nil, nil, nil) // BAD (sensitive data)
let _ = sqlite3_exec(db, deleteQuery, nil, nil, nil) // GOOD
// --- sensitive data in bindings ---
let varQuery = "UPDATE PATIENTS SET NOTES=? WHERE ID=?;"
var stmt1: OpaquePointer?
if (sqlite3_prepare(db, varQuery, -1, &stmt1, nil) == SQLITE_OK) { // GOOD
if (sqlite3_bind_int(stmt1, 1, id) == SQLITE_OK) { // GOOD
if (sqlite3_bind_text(stmt1, 2, medicalNotes, -1, SQLITE_TRANSIENT) == SQLITE_OK) { // BAD (sensitive data)
// ...
}
}
}
}