diff --git a/unified/ql/lib/codeql/unified/security/SensitiveData.qll b/unified/ql/lib/codeql/unified/security/SensitiveData.qll new file mode 100644 index 000000000000..553488c00704 --- /dev/null +++ b/unified/ql/lib/codeql/unified/security/SensitiveData.qll @@ -0,0 +1,77 @@ +/** + * Provides classes and predicates for identifying sensitive data. + * + * 'Sensitive' data is anything that should not be sent in unencrypted form. This library tries to + * guess where sensitive data may either be stored in a variable or produced by a method. + */ + +import unified +import codeql.concepts.internal.SensitiveDataHeuristics +private import codeql.unified.internal.typeinference.TypeInference as TypeInference + +/** + * A data flow node that might contain sensitive data. + */ +cached +abstract class SensitiveData extends DataFlow::Node { + /** + * Gets the classification of sensitive data this expression might contain. + */ + cached + abstract SensitiveDataClassification getClassification(); +} + +/** + * An identifier that might contain sensitive data. + */ +private class SensitiveDataIdentifier extends SensitiveData { + SensitiveDataClassification classification; + + SensitiveDataIdentifier() { + exists(IdentifierExpr e | e = this.asExpr() | + HeuristicNames::nameIndicatesSensitiveData(e.getValue(), classification) + ) + } + + override SensitiveDataClassification getClassification() { result = classification } +} + +private Expr memberAccessParent(MemberAccessExpr e) { result = e.getParent() } + +/** + * A member access that might contain sensitive data. This includes a member itself and + * components of a receiver chain, for example: + * ``` + * object.password + * password.value + * password.getValue() + * ``` + */ +private class SensitiveDataMemberAccess extends SensitiveData { + SensitiveDataClassification classification; + + SensitiveDataMemberAccess() { + exists(MemberAccessExpr e | memberAccessParent*(e) = this.asExpr() | + HeuristicNames::nameIndicatesSensitiveData(e.getMemberName(), classification) + ) + } + + override SensitiveDataClassification getClassification() { result = classification } +} + +/** + * A function call that might produce sensitive data. + */ +private class SensitiveDataCall extends SensitiveData { + SensitiveDataClassification classification; + + SensitiveDataCall() { + exists(CallExpr call, string name | + call = this.asExpr() and + name = TypeInference::resolveCallTarget(call).(Member).getNameNode().getValue() and + HeuristicNames::nameIndicatesSensitiveData(name, classification) + ) + } + + override SensitiveDataClassification getClassification() { result = classification } +} diff --git a/unified/ql/src/queries/security/CWE-312/CleartextLogging.ql b/unified/ql/src/queries/security/CWE-312/CleartextLogging.ql index 4aa751a1e91a..7f72eb6ed7e0 100644 --- a/unified/ql/src/queries/security/CWE-312/CleartextLogging.ql +++ b/unified/ql/src/queries/security/CWE-312/CleartextLogging.ql @@ -17,7 +17,7 @@ // FIXME: This is a deliberately dumb and noisy version of the query used to exercise data flow early on. // import unified -import codeql.concepts.internal.SensitiveDataHeuristics +import codeql.unified.security.SensitiveData private string getNameFromExpr(Expr e) { result = e.(IdentifierExpr).getValue() @@ -25,13 +25,11 @@ private string getNameFromExpr(Expr e) { result = e.(MemberAccessExpr).getMemberName() } -module DummyConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node node) { - exists(string name | - name = getNameFromExpr(node.asExpr()) and - HeuristicNames::nameIndicatesSensitiveData(name) - ) - } +/** + * A taint-tracking configuration for cleartext logging vulnerabilities. + */ +module CleartextLoggingConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { node instanceof SensitiveData } predicate isSink(DataFlow::Node node) { exists(CallExpr call | @@ -43,10 +41,11 @@ module DummyConfig implements DataFlow::ConfigSig { predicate isBarrierIn(DataFlow::Node node) { isSource(node) } } -module DummyFlow = TaintTracking::Global; +module CleartextLoggingFlow = TaintTracking::Global; -import DummyFlow::PathGraph +import CleartextLoggingFlow::PathGraph -from DummyFlow::PathNode source, DummyFlow::PathNode sink -where DummyFlow::flowPath(source, sink) -select sink.getNode(), source, sink, "Logging of $@", source.getNode(), "sensitive data" +from CleartextLoggingFlow::PathNode source, CleartextLoggingFlow::PathNode sink +where CleartextLoggingFlow::flowPath(source, sink) +select source.getNode(), source, sink, "This sensitive information is to $@ to a log file.", sink, + "written" diff --git a/unified/ql/test/query-tests/security/CWE-312/CleartextLogging/CleartextLogging.expected b/unified/ql/test/query-tests/security/CWE-312/CleartextLogging/CleartextLogging.expected index cb3f1cb61f2f..bce43bade02b 100644 --- a/unified/ql/test/query-tests/security/CWE-312/CleartextLogging/CleartextLogging.expected +++ b/unified/ql/test/query-tests/security/CWE-312/CleartextLogging/CleartextLogging.expected @@ -1,8 +1,128 @@ #select -| CleartextLoggingBad.swift:2:7:2:44 | StringInterpolationExpr | CleartextLoggingBad.swift:2:35:2:42 | password | CleartextLoggingBad.swift:2:7:2:44 | StringInterpolationExpr | Logging of $@ | CleartextLoggingBad.swift:2:35:2:42 | password | sensitive data | +| CleartextLoggingBad.swift:2:35:2:42 | password | CleartextLoggingBad.swift:2:35:2:42 | password | CleartextLoggingBad.swift:2:7:2:44 | StringInterpolationExpr | This sensitive information is to $@ to a log file. | CleartextLoggingBad.swift:2:7:2:44 | StringInterpolationExpr | written | +| CleartextLoggingTest.swift:167:11:167:18 | password | CleartextLoggingTest.swift:167:11:167:18 | password | CleartextLoggingTest.swift:167:11:167:18 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:167:11:167:18 | password | written | +| CleartextLoggingTest.swift:168:11:168:18 | password | CleartextLoggingTest.swift:168:11:168:18 | password | CleartextLoggingTest.swift:168:11:168:18 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:168:11:168:18 | password | written | +| CleartextLoggingTest.swift:169:26:169:33 | password | CleartextLoggingTest.swift:169:26:169:33 | password | CleartextLoggingTest.swift:169:26:169:33 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:169:26:169:33 | password | written | +| CleartextLoggingTest.swift:170:11:170:18 | password | CleartextLoggingTest.swift:170:11:170:18 | password | CleartextLoggingTest.swift:170:11:170:18 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:170:11:170:18 | password | written | +| CleartextLoggingTest.swift:171:26:171:33 | password | CleartextLoggingTest.swift:171:26:171:33 | password | CleartextLoggingTest.swift:171:26:171:33 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:171:26:171:33 | password | written | +| CleartextLoggingTest.swift:172:42:172:49 | password | CleartextLoggingTest.swift:172:42:172:49 | password | CleartextLoggingTest.swift:172:42:172:49 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:172:42:172:49 | password | written | +| CleartextLoggingTest.swift:179:11:179:18 | password | CleartextLoggingTest.swift:179:11:179:18 | password | CleartextLoggingTest.swift:179:11:179:18 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:179:11:179:18 | password | written | +| CleartextLoggingTest.swift:180:17:180:24 | password | CleartextLoggingTest.swift:180:17:180:24 | password | CleartextLoggingTest.swift:180:17:180:24 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:180:17:180:24 | password | written | +| CleartextLoggingTest.swift:181:24:181:31 | password | CleartextLoggingTest.swift:181:24:181:31 | password | CleartextLoggingTest.swift:181:24:181:31 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:181:24:181:31 | password | written | +| CleartextLoggingTest.swift:182:14:182:21 | password | CleartextLoggingTest.swift:182:14:182:21 | password | CleartextLoggingTest.swift:182:11:182:23 | StringInterpolationExpr | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:182:11:182:23 | StringInterpolationExpr | written | +| CleartextLoggingTest.swift:183:29:183:36 | password | CleartextLoggingTest.swift:183:29:183:36 | password | CleartextLoggingTest.swift:183:18:183:38 | getVaList(...) | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:183:18:183:38 | getVaList(...) | written | +| CleartextLoggingTest.swift:184:36:184:43 | password | CleartextLoggingTest.swift:184:36:184:43 | password | CleartextLoggingTest.swift:184:21:184:45 | getVaList(...) | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:184:21:184:45 | getVaList(...) | written | +| CleartextLoggingTest.swift:191:16:191:23 | password | CleartextLoggingTest.swift:191:16:191:23 | password | CleartextLoggingTest.swift:191:13:191:25 | StringInterpolationExpr | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:191:13:191:25 | StringInterpolationExpr | written | +| CleartextLoggingTest.swift:197:16:197:26 | bankAccount | CleartextLoggingTest.swift:197:16:197:26 | bankAccount | CleartextLoggingTest.swift:197:13:197:28 | StringInterpolationExpr | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:197:13:197:28 | StringInterpolationExpr | written | +| CleartextLoggingTest.swift:220:11:220:20 | passphrase | CleartextLoggingTest.swift:220:11:220:20 | passphrase | CleartextLoggingTest.swift:220:11:220:20 | passphrase | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:220:11:220:20 | passphrase | written | +| CleartextLoggingTest.swift:221:11:221:21 | pass_phrase | CleartextLoggingTest.swift:221:11:221:21 | pass_phrase | CleartextLoggingTest.swift:221:11:221:21 | pass_phrase | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:221:11:221:21 | pass_phrase | written | +| CleartextLoggingTest.swift:245:10:245:22 | getPassword(...) | CleartextLoggingTest.swift:245:10:245:22 | getPassword(...) | CleartextLoggingTest.swift:246:8:246:8 | y | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:246:8:246:8 | y | written | +| CleartextLoggingTest.swift:250:8:250:17 | ... .password | CleartextLoggingTest.swift:250:8:250:17 | ... .password | CleartextLoggingTest.swift:250:8:250:17 | ... .password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:250:8:250:17 | ... .password | written | +| CleartextLoggingTest.swift:251:8:251:22 | ... .getPassword(...) | CleartextLoggingTest.swift:251:8:251:22 | ... .getPassword(...) | CleartextLoggingTest.swift:251:8:251:22 | ... .getPassword(...) | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:251:8:251:22 | ... .getPassword(...) | written | +| CleartextLoggingTest.swift:268:8:268:24 | ... .value | CleartextLoggingTest.swift:268:8:268:24 | ... .value | CleartextLoggingTest.swift:268:8:268:24 | ... .value | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:268:8:268:24 | ... .value | written | +| CleartextLoggingTest.swift:271:8:271:29 | ... .getValue(...) | CleartextLoggingTest.swift:271:8:271:29 | ... .getValue(...) | CleartextLoggingTest.swift:271:8:271:29 | ... .getValue(...) | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:271:8:271:29 | ... .getValue(...) | written | +| CleartextLoggingTest.swift:294:8:294:15 | password | CleartextLoggingTest.swift:294:8:294:15 | password | CleartextLoggingTest.swift:294:8:294:15 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:294:8:294:15 | password | written | +| CleartextLoggingTest.swift:297:18:297:25 | password | CleartextLoggingTest.swift:297:18:297:25 | password | CleartextLoggingTest.swift:297:8:297:25 | ... + ... | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:297:8:297:25 | ... + ... | written | +| CleartextLoggingTest.swift:315:18:315:25 | password | CleartextLoggingTest.swift:315:18:315:25 | password | CleartextLoggingTest.swift:316:8:316:16 | myString9 | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:316:8:316:16 | myString9 | written | +| CleartextLoggingTest.swift:319:19:319:26 | password | CleartextLoggingTest.swift:319:19:319:26 | password | CleartextLoggingTest.swift:321:8:321:17 | myString10 | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:321:8:321:17 | myString10 | written | +| CleartextLoggingTest.swift:326:2:326:9 | password | CleartextLoggingTest.swift:326:2:326:9 | password | CleartextLoggingTest.swift:327:8:327:17 | myString12 | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:327:8:327:17 | myString12 | written | +| CleartextLoggingTest.swift:329:8:329:15 | password | CleartextLoggingTest.swift:329:8:329:15 | password | CleartextLoggingTest.swift:329:8:329:15 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:329:8:329:15 | password | written | +| CleartextLoggingTest.swift:373:18:373:24 | authKey | CleartextLoggingTest.swift:373:18:373:24 | authKey | CleartextLoggingTest.swift:373:18:373:24 | authKey | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:373:18:373:24 | authKey | written | +| CleartextLoggingTest.swift:374:25:374:32 | authKey2 | CleartextLoggingTest.swift:374:25:374:32 | authKey2 | CleartextLoggingTest.swift:374:18:374:33 | String(...) | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:374:18:374:33 | String(...) | written | +| CleartextLoggingTest.swift:375:22:375:28 | authKey | CleartextLoggingTest.swift:375:22:375:28 | authKey | CleartextLoggingTest.swift:375:22:375:28 | authKey | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:375:22:375:28 | authKey | written | +| CleartextLoggingTest.swift:376:31:376:37 | authKey | CleartextLoggingTest.swift:376:31:376:37 | authKey | CleartextLoggingTest.swift:376:31:376:37 | authKey | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:376:31:376:37 | authKey | written | +| CleartextLoggingTest.swift:377:33:377:39 | authKey | CleartextLoggingTest.swift:377:33:377:39 | authKey | CleartextLoggingTest.swift:377:16:377:40 | NSString(...) | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:377:16:377:40 | NSString(...) | written | +| CleartextLoggingTest.swift:378:13:378:19 | authKey | CleartextLoggingTest.swift:378:13:378:19 | authKey | CleartextLoggingTest.swift:378:13:378:19 | authKey | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:378:13:378:19 | authKey | written | +| CleartextLoggingTest.swift:379:24:379:30 | authKey | CleartextLoggingTest.swift:379:24:379:30 | authKey | CleartextLoggingTest.swift:379:24:379:30 | authKey | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:379:24:379:30 | authKey | written | +| CleartextLoggingTest.swift:381:19:381:26 | authKey3 | CleartextLoggingTest.swift:381:19:381:26 | authKey3 | CleartextLoggingTest.swift:381:19:381:26 | authKey3 | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:381:19:381:26 | authKey3 | written | +| CleartextLoggingTest.swift:385:29:385:35 | authKey | CleartextLoggingTest.swift:385:29:385:35 | authKey | CleartextLoggingTest.swift:386:16:386:18 | msg | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:386:16:386:18 | msg | written | +| CleartextLoggingTest.swift:385:29:385:35 | authKey | CleartextLoggingTest.swift:385:29:385:35 | authKey | CleartextLoggingTest.swift:391:20:391:22 | msg | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:391:20:391:22 | msg | written | +| CleartextLoggingTest.swift:385:29:385:35 | authKey | CleartextLoggingTest.swift:385:29:385:35 | authKey | CleartextLoggingTest.swift:392:18:392:20 | msg | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:392:18:392:20 | msg | written | +| CleartextLoggingTest.swift:402:29:402:36 | password | CleartextLoggingTest.swift:402:29:402:36 | password | CleartextLoggingTest.swift:402:29:402:36 | password | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:402:29:402:36 | password | written | +| CleartextLoggingTest.swift:403:28:403:33 | secret | CleartextLoggingTest.swift:403:28:403:33 | secret | CleartextLoggingTest.swift:403:28:403:33 | secret | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:403:28:403:33 | secret | written | +| CleartextLoggingTest.swift:411:11:411:24 | globalPassword | CleartextLoggingTest.swift:411:11:411:24 | globalPassword | CleartextLoggingTest.swift:411:11:411:24 | globalPassword | This sensitive information is to $@ to a log file. | CleartextLoggingTest.swift:411:11:411:24 | globalPassword | written | edges | CleartextLoggingBad.swift:2:35:2:42 | password | CleartextLoggingBad.swift:2:7:2:44 | StringInterpolationExpr | provenance | | +| CleartextLoggingTest.swift:182:14:182:21 | password | CleartextLoggingTest.swift:182:11:182:23 | StringInterpolationExpr | provenance | | +| CleartextLoggingTest.swift:183:28:183:37 | ArrayLiteral [ArrayElement] | CleartextLoggingTest.swift:183:18:183:38 | getVaList(...) | provenance | | +| CleartextLoggingTest.swift:183:29:183:36 | password | CleartextLoggingTest.swift:183:28:183:37 | ArrayLiteral [ArrayElement] | provenance | | +| CleartextLoggingTest.swift:184:31:184:44 | ArrayLiteral [ArrayElement] | CleartextLoggingTest.swift:184:21:184:45 | getVaList(...) | provenance | | +| CleartextLoggingTest.swift:184:36:184:43 | password | CleartextLoggingTest.swift:184:31:184:44 | ArrayLiteral [ArrayElement] | provenance | | +| CleartextLoggingTest.swift:191:16:191:23 | password | CleartextLoggingTest.swift:191:13:191:25 | StringInterpolationExpr | provenance | | +| CleartextLoggingTest.swift:197:16:197:26 | bankAccount | CleartextLoggingTest.swift:197:13:197:28 | StringInterpolationExpr | provenance | | +| CleartextLoggingTest.swift:245:6:245:6 | y | CleartextLoggingTest.swift:246:8:246:8 | y | provenance | | +| CleartextLoggingTest.swift:245:10:245:22 | getPassword(...) | CleartextLoggingTest.swift:245:6:245:6 | y | provenance | | +| CleartextLoggingTest.swift:297:18:297:25 | password | CleartextLoggingTest.swift:297:8:297:25 | ... + ... | provenance | | +| CleartextLoggingTest.swift:315:18:315:25 | password | CleartextLoggingTest.swift:316:8:316:16 | myString9 | provenance | | +| CleartextLoggingTest.swift:319:19:319:26 | password | CleartextLoggingTest.swift:321:8:321:17 | myString10 | provenance | | +| CleartextLoggingTest.swift:326:2:326:9 | password | CleartextLoggingTest.swift:326:21:326:31 | [post] & ... | provenance | | +| CleartextLoggingTest.swift:326:21:326:31 | [post] & ... | CleartextLoggingTest.swift:327:8:327:17 | myString12 | provenance | | +| CleartextLoggingTest.swift:374:25:374:32 | authKey2 | CleartextLoggingTest.swift:374:18:374:33 | String(...) | provenance | | +| CleartextLoggingTest.swift:377:33:377:39 | authKey | CleartextLoggingTest.swift:377:16:377:40 | NSString(...) | provenance | | +| CleartextLoggingTest.swift:385:9:385:11 | msg | CleartextLoggingTest.swift:386:16:386:18 | msg | provenance | | +| CleartextLoggingTest.swift:385:9:385:11 | msg | CleartextLoggingTest.swift:391:20:391:22 | msg | provenance | | +| CleartextLoggingTest.swift:385:9:385:11 | msg | CleartextLoggingTest.swift:392:18:392:20 | msg | provenance | | +| CleartextLoggingTest.swift:385:29:385:35 | authKey | CleartextLoggingTest.swift:385:9:385:11 | msg | provenance | | nodes | CleartextLoggingBad.swift:2:7:2:44 | StringInterpolationExpr | semmle.label | StringInterpolationExpr | | CleartextLoggingBad.swift:2:35:2:42 | password | semmle.label | password | +| CleartextLoggingTest.swift:167:11:167:18 | password | semmle.label | password | +| CleartextLoggingTest.swift:168:11:168:18 | password | semmle.label | password | +| CleartextLoggingTest.swift:169:26:169:33 | password | semmle.label | password | +| CleartextLoggingTest.swift:170:11:170:18 | password | semmle.label | password | +| CleartextLoggingTest.swift:171:26:171:33 | password | semmle.label | password | +| CleartextLoggingTest.swift:172:42:172:49 | password | semmle.label | password | +| CleartextLoggingTest.swift:179:11:179:18 | password | semmle.label | password | +| CleartextLoggingTest.swift:180:17:180:24 | password | semmle.label | password | +| CleartextLoggingTest.swift:181:24:181:31 | password | semmle.label | password | +| CleartextLoggingTest.swift:182:11:182:23 | StringInterpolationExpr | semmle.label | StringInterpolationExpr | +| CleartextLoggingTest.swift:182:14:182:21 | password | semmle.label | password | +| CleartextLoggingTest.swift:183:18:183:38 | getVaList(...) | semmle.label | getVaList(...) | +| CleartextLoggingTest.swift:183:28:183:37 | ArrayLiteral [ArrayElement] | semmle.label | ArrayLiteral [ArrayElement] | +| CleartextLoggingTest.swift:183:29:183:36 | password | semmle.label | password | +| CleartextLoggingTest.swift:184:21:184:45 | getVaList(...) | semmle.label | getVaList(...) | +| CleartextLoggingTest.swift:184:31:184:44 | ArrayLiteral [ArrayElement] | semmle.label | ArrayLiteral [ArrayElement] | +| CleartextLoggingTest.swift:184:36:184:43 | password | semmle.label | password | +| CleartextLoggingTest.swift:191:13:191:25 | StringInterpolationExpr | semmle.label | StringInterpolationExpr | +| CleartextLoggingTest.swift:191:16:191:23 | password | semmle.label | password | +| CleartextLoggingTest.swift:197:13:197:28 | StringInterpolationExpr | semmle.label | StringInterpolationExpr | +| CleartextLoggingTest.swift:197:16:197:26 | bankAccount | semmle.label | bankAccount | +| CleartextLoggingTest.swift:220:11:220:20 | passphrase | semmle.label | passphrase | +| CleartextLoggingTest.swift:221:11:221:21 | pass_phrase | semmle.label | pass_phrase | +| CleartextLoggingTest.swift:245:6:245:6 | y | semmle.label | y | +| CleartextLoggingTest.swift:245:10:245:22 | getPassword(...) | semmle.label | getPassword(...) | +| CleartextLoggingTest.swift:246:8:246:8 | y | semmle.label | y | +| CleartextLoggingTest.swift:250:8:250:17 | ... .password | semmle.label | ... .password | +| CleartextLoggingTest.swift:251:8:251:22 | ... .getPassword(...) | semmle.label | ... .getPassword(...) | +| CleartextLoggingTest.swift:268:8:268:24 | ... .value | semmle.label | ... .value | +| CleartextLoggingTest.swift:271:8:271:29 | ... .getValue(...) | semmle.label | ... .getValue(...) | +| CleartextLoggingTest.swift:294:8:294:15 | password | semmle.label | password | +| CleartextLoggingTest.swift:297:8:297:25 | ... + ... | semmle.label | ... + ... | +| CleartextLoggingTest.swift:297:18:297:25 | password | semmle.label | password | +| CleartextLoggingTest.swift:315:18:315:25 | password | semmle.label | password | +| CleartextLoggingTest.swift:316:8:316:16 | myString9 | semmle.label | myString9 | +| CleartextLoggingTest.swift:319:19:319:26 | password | semmle.label | password | +| CleartextLoggingTest.swift:321:8:321:17 | myString10 | semmle.label | myString10 | +| CleartextLoggingTest.swift:326:2:326:9 | password | semmle.label | password | +| CleartextLoggingTest.swift:326:21:326:31 | [post] & ... | semmle.label | [post] & ... | +| CleartextLoggingTest.swift:327:8:327:17 | myString12 | semmle.label | myString12 | +| CleartextLoggingTest.swift:329:8:329:15 | password | semmle.label | password | +| CleartextLoggingTest.swift:373:18:373:24 | authKey | semmle.label | authKey | +| CleartextLoggingTest.swift:374:18:374:33 | String(...) | semmle.label | String(...) | +| CleartextLoggingTest.swift:374:25:374:32 | authKey2 | semmle.label | authKey2 | +| CleartextLoggingTest.swift:375:22:375:28 | authKey | semmle.label | authKey | +| CleartextLoggingTest.swift:376:31:376:37 | authKey | semmle.label | authKey | +| CleartextLoggingTest.swift:377:16:377:40 | NSString(...) | semmle.label | NSString(...) | +| CleartextLoggingTest.swift:377:33:377:39 | authKey | semmle.label | authKey | +| CleartextLoggingTest.swift:378:13:378:19 | authKey | semmle.label | authKey | +| CleartextLoggingTest.swift:379:24:379:30 | authKey | semmle.label | authKey | +| CleartextLoggingTest.swift:381:19:381:26 | authKey3 | semmle.label | authKey3 | +| CleartextLoggingTest.swift:385:9:385:11 | msg | semmle.label | msg | +| CleartextLoggingTest.swift:385:29:385:35 | authKey | semmle.label | authKey | +| CleartextLoggingTest.swift:386:16:386:18 | msg | semmle.label | msg | +| CleartextLoggingTest.swift:391:20:391:22 | msg | semmle.label | msg | +| CleartextLoggingTest.swift:392:18:392:20 | msg | semmle.label | msg | +| CleartextLoggingTest.swift:402:29:402:36 | password | semmle.label | password | +| CleartextLoggingTest.swift:403:28:403:33 | secret | semmle.label | secret | +| CleartextLoggingTest.swift:411:11:411:24 | globalPassword | semmle.label | globalPassword | subpaths diff --git a/unified/ql/test/query-tests/security/CWE-312/CleartextLogging/CleartextLoggingTest.swift b/unified/ql/test/query-tests/security/CWE-312/CleartextLogging/CleartextLoggingTest.swift new file mode 100644 index 000000000000..38c20943ea1a --- /dev/null +++ b/unified/ql/test/query-tests/security/CWE-312/CleartextLogging/CleartextLoggingTest.swift @@ -0,0 +1,436 @@ +// --- stubs --- + +class NSObject { } + +func NSLog(_ format: String, _ args: CVarArg...) {} +func NSLogv(_ format: String, _ args: CVaListPointer) {} + +func getVaList(_ args: [CVarArg]) -> CVaListPointer { return CVaListPointer(_fromUnsafeMutablePointer: UnsafeMutablePointer(bitPattern: 0)!) } + +struct OSLogType : RawRepresentable { + static let `default` = OSLogType(rawValue: 0) + let rawValue: UInt8 + init(rawValue: UInt8) { self.rawValue = rawValue} +} + +struct OSLogStringAlignment { + static var none = OSLogStringAlignment() +} + +enum OSLogIntegerFormatting { case decimal } +enum OSLogInt32ExtendedFormat { case none } +enum OSLogFloatFormatting { case fixed } +enum OSLogBoolFormat { case truth } + +struct OSLogPrivacy { + enum Mask { case none } + static var auto = OSLogPrivacy() + static var `private` = OSLogPrivacy() + static var `public` = OSLogPrivacy() + static var sensitive = OSLogPrivacy() + + static func auto(mask: OSLogPrivacy.Mask) -> OSLogPrivacy { return .auto } + static func `private`(mask: OSLogPrivacy.Mask) -> OSLogPrivacy { return .private } + static func `sensitive`(mask: OSLogPrivacy.Mask) -> OSLogPrivacy { return .sensitive } +} + +struct OSLogInterpolation : StringInterpolationProtocol { + typealias StringLiteralType = String + init(literalCapacity: Int, interpolationCount: Int) {} + func appendLiteral(_: Self.StringLiteralType) {} + mutating func appendInterpolation(_ argumentString: @autoclosure @escaping () -> String, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ argumentString: @autoclosure @escaping () -> String, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto, attributes: String) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Int, format: OSLogIntegerFormatting = .decimal, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Int8, format: OSLogIntegerFormatting = .decimal, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Int16, format: OSLogIntegerFormatting = .decimal, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Int32, format: OSLogInt32ExtendedFormat, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Int32, format: OSLogInt32ExtendedFormat, privacy: OSLogPrivacy = .auto, attributes: String) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Int32, format: OSLogIntegerFormatting = .decimal, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Int64, format: OSLogIntegerFormatting = .decimal, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> UInt, format: OSLogIntegerFormatting = .decimal, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> UInt8, format: OSLogIntegerFormatting = .decimal, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> UInt16, format: OSLogIntegerFormatting = .decimal, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> UInt32, format: OSLogIntegerFormatting = .decimal, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> UInt64, format: OSLogIntegerFormatting = .decimal, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Double, format: OSLogFloatFormatting = .fixed, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Double, format: OSLogFloatFormatting = .fixed, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto, attributes: String) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Float,format: OSLogFloatFormatting = .fixed, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto) {} + mutating func appendInterpolation(_ number: @autoclosure @escaping () -> Float, format: OSLogFloatFormatting = .fixed, align: OSLogStringAlignment = .none, privacy: OSLogPrivacy = .auto, attributes: String) {} + mutating func appendInterpolation(_ boolean: @autoclosure @escaping () -> Bool, format: OSLogBoolFormat = .truth, privacy: OSLogPrivacy = .auto) {} +} + +struct OSLogMessage : ExpressibleByStringInterpolation { + typealias StringInterpolation = OSLogInterpolation + typealias StringLiteralType = String + typealias ExtendedGraphemeClusterLiteralType = String + typealias UnicodeScalarLiteralType = String + init(stringInterpolation: OSLogInterpolation) {} + init(stringLiteral: String) {} + init(extendedGraphemeClusterLiteral: String) {} + init(unicodeScalarLiteral: String) {} +} + +struct Logger { + func log(_ message: OSLogMessage) {} + func log(level: OSLogType, _ message: OSLogMessage) {} + func notice(_: OSLogMessage) {} + func debug(_: OSLogMessage) {} + func trace(_: OSLogMessage) {} + func info(_: OSLogMessage) {} + func error(_: OSLogMessage) {} + func warning(_: OSLogMessage) {} + func fault(_: OSLogMessage) {} + func critical(_: OSLogMessage) {} +} + +class OSLog : NSObject { + static let `default` = OSLog(rawValue: 0) + let rawValue: UInt8 + init(rawValue: UInt8) { self.rawValue = rawValue} +} + +extension String : CVarArg { + public var _cVarArgEncoding: [Int] { get { return [] } } +} + +struct NSExceptionName { + init(_ rawValue: String) {} +} + +class NSException : NSObject +{ + init(name aName: NSExceptionName, reason aReason: String?, userInfo aUserInfo: [AnyHashable : Any]? = nil) {} + class func raise(_ name: NSExceptionName, format: String, arguments argList: CVaListPointer) {} + func raise() {} +} + +class NSString : NSObject { + convenience init(string aString: String) { self.init() } +} + +// from ObjC API; slightly simplified. +func os_log(_ message: StaticString, + dso: UnsafeRawPointer? = nil, + log: OSLog = .default, + type: OSLogType = .default, + _ args: CVarArg...) { } + +// imported from C +typealias FILE = Int32 // this is a simplification +typealias wchar_t = Int32 +typealias locale_t = OpaquePointer +func dprintf(_ fd: Int, _ format: UnsafePointer, _ args: CVarArg...) -> Int32 { return 0 } +func vprintf(_ format: UnsafePointer, _ arg: CVaListPointer) -> Int32 { return 0 } +func vfprintf(_ file: UnsafeMutablePointer?, _ format: UnsafePointer?, _ arg: CVaListPointer) -> Int32 { return 0 } +func vasprintf_l(_ ret: UnsafeMutablePointer?>?, _ loc: locale_t?, _ format: UnsafePointer?, _ ap: CVaListPointer) -> Int32 { return 0 } + +// custom +func log(message: String) {} +func logging(message: String) {} +func logfile(file: Int, message: String) {} +func logMessage(_ msg: NSString) {} +func logInfo(_ infoMsg: String) {} +func logError(errorMsg str: String) {} +func harmless(_ str: String) {} // safe +func logarithm(_ val: Float) -> Float { return 0.0 } // safe +func doLogin(login: String) {} // safe + +// custom +class LogFile { + func log(_ str: String) {} + func trace(_ message: String?) {} + func debug(_ message: String) {} + func info(_ info: NSString) {} + func notice(_ notice: String) {} + func warning(_ warningMessage: String) {} + func error(_ msg: String) {} + func critical(_ criticalMsg: String) {} + func fatal(_ str: String) {} +} + +// custom +class Logic { + func addInt(_ val: Int) {} // safe + func addString(_ str: String) {} // safe +} + +// custom +class MyRemoteLogger { + func setPassword(password: String) { } + func login(password: String) { } + func logout(secret: String) { } +} + +// --- tests --- + +func test1(password: String, passwordHash : String, passphrase: String, pass_phrase: String) { + print(password) // $ Alert[unified/swift/cleartext-logging] + print(password, separator: "") // $ Alert[unified/swift/cleartext-logging] + print("", separator: password) // $ Alert[unified/swift/cleartext-logging] + print(password, separator: "", terminator: "") // $ Alert[unified/swift/cleartext-logging] + print("", separator: password, terminator: "") // $ Alert[unified/swift/cleartext-logging] + print("", separator: "", terminator: password) // $ Alert[unified/swift/cleartext-logging] + print(passwordHash) // safe + + debugPrint(password) // $ MISSING: Alert[unified/swift/cleartext-logging] + + dump(password) // $ MISSING: Alert[unified/swift/cleartext-logging] + + NSLog(password) // $ Alert[unified/swift/cleartext-logging] + NSLog("%@", password) // $ Alert[unified/swift/cleartext-logging] + NSLog("%@ %@", "", password) // $ Alert[unified/swift/cleartext-logging] + NSLog("\(password)") // $ Alert[unified/swift/cleartext-logging] + NSLogv("%@", getVaList([password])) // $ Alert[unified/swift/cleartext-logging] + NSLogv("%@ %@", getVaList(["", password])) // $ Alert[unified/swift/cleartext-logging] + NSLog(passwordHash) // safe + NSLogv("%@", getVaList([passwordHash])) // safe + + let bankAccount: Int = 0 + let log = Logger() + // These MISSING test cases will be fixed when we properly generate the CFG around autoclosures. + log.log("\(password)") // $ SPURIOUS: Alert[unified/swift/cleartext-logging] safe + log.log("\(password, privacy: .auto)") // safe + log.log("\(password, privacy: .private)") // safe + log.log("\(password, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.log("\(passwordHash, privacy: .public)") // safe + log.log("\(password, privacy: .sensitive)") // safe + log.log("\(bankAccount)") // $ Alert[unified/swift/cleartext-logging] + log.log("\(bankAccount, privacy: .auto)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.log("\(bankAccount, privacy: .private)") // safe + log.log("\(bankAccount, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.log("\(bankAccount, privacy: .sensitive)") // safe + log.log(level: .default, "\(password, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.trace("\(password, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.trace("\(passwordHash, privacy: .public)") // safe + log.debug("\(password, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.debug("\(passwordHash, privacy: .public)") // safe + log.info("\(password, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.info("\(passwordHash, privacy: .public)") // safe + log.notice("\(password, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.notice("\(passwordHash, privacy: .public)") // safe + log.warning("\(password, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.warning("\(passwordHash, privacy: .public)") // safe + log.error("\(password, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.error("\(passwordHash, privacy: .public)") // safe + log.critical("\(password, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.critical("\(passwordHash, privacy: .public)") // safe + log.fault("\(password, privacy: .public)") // $ MISSING: Alert[unified/swift/cleartext-logging] + log.fault("\(passwordHash, privacy: .public)") // safe + + NSLog(passphrase) // $ Alert[unified/swift/cleartext-logging] + NSLog(pass_phrase) // $ Alert[unified/swift/cleartext-logging] + + os_log("%@", log: .default, type: .default, "") // safe + os_log("%@", log: .default, type: .default, password) // $ MISSING: Alert[unified/swift/cleartext-logging] + os_log("%@ %@ %@", log: .default, type: .default, "", "", password) // $ MISSING: Alert[unified/swift/cleartext-logging] +} + +class MyClass { + var harmless = "abc" + var password = "123" + + func getPassword() -> String { return "" } +} + +func getPassword() -> String { return "" } +func doSomething(password: String) { } + +func test3(x: String) { + // alternative evidence of sensitivity... + + NSLog(x) // $ MISSING: Alert + doSomething(password: x); // $ MISSING: Source[unified/swift/cleartext-logging] + NSLog(x) // $ MISSING: Alert[unified/swift/cleartext-logging] + + let y = getPassword(); // $ Alert[unified/swift/cleartext-logging] + NSLog(y) // $ Sink[unified/swift/cleartext-logging] + + let z = MyClass() + NSLog(z.harmless) // safe + NSLog(z.password) // $ Alert[unified/swift/cleartext-logging] + NSLog(z.getPassword()) // $ Alert[unified/swift/cleartext-logging] +} + +struct MyOuter { + struct MyInner { + var value: String + + func getValue() -> String { return "" } + } + + var password: MyInner + var harmless: MyInner +} + +func test3(mo : MyOuter) { + // struct members... + + NSLog(mo.password.value) // $ Alert[unified/swift/cleartext-logging] + NSLog(mo.harmless.value) // safe + + NSLog(mo.password.getValue()) // $ Alert[unified/swift/cleartext-logging] + NSLog(mo.harmless.getValue()) // safe +} + +func test4(harmless: String, password: String) { + // functions with an `in:` target for the write... + var myString1 = "" + var myString2 = "" + var myString3 = "" + var myString4 = "" + var myString5 = "" + var myString6 = "" + var myString7 = "" + var myString8 = "" + var myString9 = "" + var myString10 = "" + var myString11 = "" + var myString12 = "" + var myString13 = "" + + print(harmless, to: &myString1) + print(myString1) // safe + + print(password, to: &myString2) // $ MISSING: Source[unified/swift/cleartext-logging] SPURIOUS: Alert[unified/swift/cleartext-logging] + print(myString2) // $ MISSING: Alert[unified/swift/cleartext-logging] + + print("log: " + password, to: &myString3) // $ MISSING: Source[unified/swift/cleartext-logging] SPURIOUS: Alert[unified/swift/cleartext-logging] + print(myString3) // $ MISSING: Alert[unified/swift/cleartext-logging] + + debugPrint(harmless, to: &myString4) + debugPrint(myString4) // safe + + debugPrint(password, to: &myString5) // $ MISSING: Source[unified/swift/cleartext-logging] + debugPrint(myString5) // $ MISSING: Alert[unified/swift/cleartext-logging] + + dump(harmless, to: &myString6) + dump(myString6) // safe + + dump(password, to: &myString7) // $ MISSING: Source[unified/swift/cleartext-logging] + dump(myString7) // $ MISSING: Alert[unified/swift/cleartext-logging] + + myString8.write(harmless) + print(myString8) + + myString9.write(password) // $ Alert[unified/swift/cleartext-logging] + print(myString9) // $ Sink[unified/swift/cleartext-logging] + + myString10.write(harmless) + myString10.write(password) // $ Alert[unified/swift/cleartext-logging] + myString10.write(harmless) + print(myString10) // $ Sink[unified/swift/cleartext-logging] + + harmless.write(to: &myString11) + print(myString11) + + password.write(to: &myString12) // $ Alert[unified/swift/cleartext-logging] + print(myString12) // $ Sink[unified/swift/cleartext-logging] + + print(password, to: &myString13) // $ SPURIOUS: Alert[unified/swift/cleartext-logging] safe - only printed to another string + debugPrint(password, to: &myString13) // safe - only printed to another string + dump(password, to: &myString13) // safe - only printed to another string + myString13.write(password) // safe - only printed to another string + password.write(to: &myString13) // safe - only printed to another string +} + +func test5(password: String, caseNum: Int) { + // `assert` methods... + // (these would only be a danger in certain builds) + + switch caseNum { + case 0: + assert(false, password) // $ MISSING: Alert[unified/swift/cleartext-logging] + case 1: + assertionFailure(password) // $ MISSING: Alert[unified/swift/cleartext-logging] + case 2: + precondition(false, password) // $ MISSING: Alert[unified/swift/cleartext-logging] + case 3: + preconditionFailure(password) // $ MISSING: Alert[unified/swift/cleartext-logging] + default: + fatalError(password) // $ MISSING: Alert[unified/swift/cleartext-logging] + } +} + +func test6(passwordString: String) { + let e = NSException(name: NSExceptionName("exception"), reason: "\(passwordString) is incorrect!", userInfo: nil) // $ MISSING: Alert[unified/swift/cleartext-logging] + e.raise() + + NSException.raise(NSExceptionName("exception"), format: "\(passwordString) is incorrect!", arguments: getVaList([])) // $ MISSING: Alert[unified/swift/cleartext-logging] + NSException.raise(NSExceptionName("exception"), format: "%s is incorrect!", arguments: getVaList([passwordString])) // $ MISSING: Alert[unified/swift/cleartext-logging] + + _ = dprintf(0, "\(passwordString) is incorrect!") // $ MISSING: Alert[unified/swift/cleartext-logging] + _ = dprintf(0, "%s is incorrect!", passwordString) // $ MISSING: Alert[unified/swift/cleartext-logging] + _ = dprintf(0, "%s: %s is incorrect!", "foo", passwordString) // $ MISSING: Alert[unified/swift/cleartext-logging] + _ = vprintf("\(passwordString) is incorrect!", getVaList([])) // $ MISSING: Alert[unified/swift/cleartext-logging] + _ = vprintf("%s is incorrect!", getVaList([passwordString])) // $ MISSING: Alert[unified/swift/cleartext-logging] + _ = vfprintf(nil, "\(passwordString) is incorrect!", getVaList([])) // $ MISSING: Alert[unified/swift/cleartext-logging] + _ = vfprintf(nil, "%s is incorrect!", getVaList([passwordString])) // $ MISSING: Alert[unified/swift/cleartext-logging] + _ = vasprintf_l(nil, nil, "\(passwordString) is incorrect!", getVaList([])) // good (`sprintf` is not logging) + _ = vasprintf_l(nil, nil, "%s is incorrect!", getVaList([passwordString])) // good (`sprintf` is not logging) +} + +func test7(authKey: String, authKey2: Int, authKey3: Float, password: String, secret: String) { + log(message: authKey) // $ Alert[unified/swift/cleartext-logging] + log(message: String(authKey2)) // $ Alert[unified/swift/cleartext-logging] + logging(message: authKey) // $ Alert[unified/swift/cleartext-logging] + logfile(file: 0, message: authKey) // $ Alert[unified/swift/cleartext-logging] + logMessage(NSString(string: authKey)) // $ Alert[unified/swift/cleartext-logging] + logInfo(authKey) // $ Alert[unified/swift/cleartext-logging] + logError(errorMsg: authKey) // $ Alert[unified/swift/cleartext-logging] + harmless(authKey) // GOOD: not logging + _ = logarithm(authKey3) // $ SPURIOUS: Alert[unified/swift/cleartext-logging] GOOD: not logging + doLogin(login: authKey) // GOOD: not logging + + let logger = LogFile() + let msg = "authKey: " + authKey // $ Alert[unified/swift/cleartext-logging] + logger.log(msg) // $ Sink[unified/swift/cleartext-logging] + logger.trace(msg) // $ MISSING: Sink[unified/swift/cleartext-logging] + logger.debug(msg) // $ MISSING: Sink[unified/swift/cleartext-logging] + logger.info(NSString(string: msg)) // $ MISSING: Sink[unified/swift/cleartext-logging] + logger.notice(msg) // $ MISSING: Sink[unified/swift/cleartext-logging] + logger.warning(msg) // $ Sink[unified/swift/cleartext-logging] + logger.error(msg) // $ Sink[unified/swift/cleartext-logging] + logger.critical(msg) // $ MISSING: Sink[unified/swift/cleartext-logging] + logger.fatal(msg) // $ MISSING: Sink[unified/swift/cleartext-logging] + + let logic = Logic() + logic.addInt(authKey2) // GOOD: not logging + logic.addString(authKey) // GOOD: not logging + + let rlogger = MyRemoteLogger() + rlogger.setPassword(password: password) // GOOD: not logging + rlogger.login(password: password) // $ SPURIOUS: Alert[unified/swift/cleartext-logging] GOOD: not logging + rlogger.logout(secret: secret) // $ SPURIOUS: Alert[unified/swift/cleartext-logging] GOOD: not logging +} + +let globalMessage = "example" +let globalPassword = "example" + +func testGlobals(a: Password, b: Info) { + print(globalMessage) // safe + print(globalPassword) // $ Alert[unified/swift/cleartext-logging] +} + +enum Password { + case value(String) +} + +enum Info { + case password(String) + case message(String) +} + +func testEnums(p: Password, i: Info) { + // print the value from the Password enum + if case .value(let contents) = p { + print(contents) // $ MISSING: Alert[unified/swift/cleartext-logging] + } + + // print the values from the Info enum + switch i { + case .password(let contents): + print(contents) // $ MISSING: Alert[unified/swift/cleartext-logging] + case .message(let contents): + print(contents) // safe + } +}