mirror of
https://github.com/github/codeql.git
synced 2026-04-25 16:55:19 +02:00
Merge branch 'main' into redsun82/swift-open-redirection
This commit is contained in:
@@ -89,6 +89,7 @@ private module Frameworks {
|
||||
private import codeql.swift.frameworks.StandardLibrary.UrlSession
|
||||
private import codeql.swift.frameworks.StandardLibrary.WebView
|
||||
private import codeql.swift.frameworks.Alamofire.Alamofire
|
||||
private import codeql.swift.security.CleartextLogging
|
||||
private import codeql.swift.security.PathInjection
|
||||
private import codeql.swift.security.PredicateInjection
|
||||
}
|
||||
|
||||
103
swift/ql/lib/codeql/swift/security/CleartextLogging.qll
Normal file
103
swift/ql/lib/codeql/swift/security/CleartextLogging.qll
Normal file
@@ -0,0 +1,103 @@
|
||||
/** Provides classes and predicates to reason about cleartext logging of sensitive data vulnerabilities. */
|
||||
|
||||
import swift
|
||||
private import codeql.swift.dataflow.DataFlow
|
||||
private import codeql.swift.dataflow.ExternalFlow
|
||||
private import codeql.swift.security.SensitiveExprs
|
||||
|
||||
/** A data flow sink for cleartext logging of sensitive data vulnerabilities. */
|
||||
abstract class CleartextLoggingSink extends DataFlow::Node { }
|
||||
|
||||
/** A sanitizer for cleartext logging of sensitive data vulnerabilities. */
|
||||
abstract class CleartextLoggingSanitizer extends DataFlow::Node { }
|
||||
|
||||
/**
|
||||
* A unit class for adding additional taint steps.
|
||||
*
|
||||
* Extend this class to add additional taint steps that should apply to paths related to
|
||||
* cleartext logging of sensitive data vulnerabilities.
|
||||
*/
|
||||
class CleartextLoggingAdditionalTaintStep extends Unit {
|
||||
/**
|
||||
* Holds if the step from `n1` to `n2` should be considered a taint
|
||||
* step for flows related to cleartext logging of sensitive data vulnerabilities.
|
||||
*/
|
||||
abstract predicate step(DataFlow::Node n1, DataFlow::Node n2);
|
||||
}
|
||||
|
||||
private class DefaultCleartextLoggingSink extends CleartextLoggingSink {
|
||||
DefaultCleartextLoggingSink() { sinkNode(this, "logging") }
|
||||
}
|
||||
|
||||
/**
|
||||
* A sanitizer for `OSLogMessage`s configured with the appropriate privacy option.
|
||||
* Numeric and boolean arguments aren't redacted unless the `private` or `sensitive` options are used.
|
||||
* Arguments of other types are always redacted unless the `public` option is used.
|
||||
*/
|
||||
private class OsLogPrivacyCleartextLoggingSanitizer extends CleartextLoggingSanitizer {
|
||||
OsLogPrivacyCleartextLoggingSanitizer() {
|
||||
exists(CallExpr c, AutoClosureExpr e |
|
||||
c.getStaticTarget().getName().matches("appendInterpolation(_:%privacy:%)") and
|
||||
c.getArgument(0).getExpr() = e and
|
||||
this.asExpr() = e
|
||||
|
|
||||
e.getExpr().getType() instanceof OsLogNonRedactedType and
|
||||
c.getArgumentWithLabel("privacy").getExpr().(OsLogPrivacyRef).isSafe()
|
||||
or
|
||||
not e.getExpr().getType() instanceof OsLogNonRedactedType and
|
||||
not c.getArgumentWithLabel("privacy").getExpr().(OsLogPrivacyRef).isPublic()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A type that isn't redacted by default in an `OSLogMessage`. */
|
||||
private class OsLogNonRedactedType extends Type {
|
||||
OsLogNonRedactedType() {
|
||||
this.getName() = [["", "U"] + "Int" + ["", "8", "16", "32", "64"], "Double", "Float", "Bool"]
|
||||
}
|
||||
}
|
||||
|
||||
/** A reference to a field of `OsLogPrivacy`. */
|
||||
private class OsLogPrivacyRef extends MemberRefExpr {
|
||||
string optionName;
|
||||
|
||||
OsLogPrivacyRef() {
|
||||
exists(FieldDecl f | this.getMember() = f |
|
||||
f.getEnclosingDecl().(NominalTypeDecl).getName() = "OSLogPrivacy" and
|
||||
optionName = f.getName()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if this is a safe privacy option (private or sensitive). */
|
||||
predicate isSafe() { optionName = ["private", "sensitive"] }
|
||||
|
||||
/** Holds if this is a public (that is, unsafe) privacy option. */
|
||||
predicate isPublic() { optionName = "public" }
|
||||
}
|
||||
|
||||
private class LoggingSinks extends SinkModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
";;false;print(_:separator:terminator:);;;Argument[0].ArrayElement;logging",
|
||||
";;false;print(_:separator:terminator:);;;Argument[1..2];logging",
|
||||
";;false;print(_:separator:terminator:toStream:);;;Argument[0].ArrayElement;logging",
|
||||
";;false;print(_:separator:terminator:toStream:);;;Argument[1..2];logging",
|
||||
";;false;NSLog(_:_:);;;Argument[0];logging",
|
||||
";;false;NSLog(_:_:);;;Argument[1].ArrayElement;logging",
|
||||
";;false;NSLogv(_:_:);;;Argument[0];logging",
|
||||
";;false;NSLogv(_:_:);;;Argument[1].ArrayElement;logging",
|
||||
";;false;vfprintf(_:_:_:);;;Agument[1..2];logging",
|
||||
";Logger;true;log(_:);;;Argument[0];logging",
|
||||
";Logger;true;log(level:_:);;;Argument[1];logging",
|
||||
";Logger;true;trace(_:);;;Argument[1];logging",
|
||||
";Logger;true;debug(_:);;;Argument[1];logging",
|
||||
";Logger;true;info(_:);;;Argument[1];logging",
|
||||
";Logger;true;notice(_:);;;Argument[1];logging",
|
||||
";Logger;true;warning(_:);;;Argument[1];logging",
|
||||
";Logger;true;error(_:);;;Argument[1];logging",
|
||||
";Logger;true;critical(_:);;;Argument[1];logging",
|
||||
";Logger;true;fault(_:);;;Argument[1];logging",
|
||||
]
|
||||
}
|
||||
}
|
||||
32
swift/ql/lib/codeql/swift/security/CleartextLoggingQuery.qll
Normal file
32
swift/ql/lib/codeql/swift/security/CleartextLoggingQuery.qll
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Provides a taint-tracking configuration for reasoning about cleartext logging of
|
||||
* sensitive data vulnerabilities.
|
||||
*/
|
||||
|
||||
import swift
|
||||
private import codeql.swift.dataflow.DataFlow
|
||||
private import codeql.swift.dataflow.TaintTracking
|
||||
private import codeql.swift.security.CleartextLogging
|
||||
private import codeql.swift.security.SensitiveExprs
|
||||
|
||||
/**
|
||||
* A taint-tracking configuration for cleartext logging of sensitive data vulnerabilities.
|
||||
*/
|
||||
class CleartextLoggingConfiguration extends TaintTracking::Configuration {
|
||||
CleartextLoggingConfiguration() { this = "CleartextLoggingConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveExpr }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof CleartextLoggingSink }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node sanitizer) {
|
||||
sanitizer instanceof CleartextLoggingSanitizer
|
||||
}
|
||||
|
||||
// Disregard paths that contain other paths. This helps with performance.
|
||||
override predicate isSanitizerIn(DataFlow::Node node) { this.isSource(node) }
|
||||
|
||||
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
any(CleartextLoggingAdditionalTaintStep s).step(n1, n2)
|
||||
}
|
||||
}
|
||||
46
swift/ql/src/queries/Security/CWE-312/CleartextLogging.qhelp
Normal file
46
swift/ql/src/queries/Security/CWE-312/CleartextLogging.qhelp
Normal file
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Attackers could gain access to sensitive information that is logged unencrypted.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
Always make sure to encrypt or obfuscate sensitive information before you log it.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Generally, you should decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Be aware that external processes often store the standard output and
|
||||
standard error streams of the application. This will include logged sensitive information.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example code logs user credentials (in this case, their password)
|
||||
in plaintext:
|
||||
</p>
|
||||
<sample src="CleartextLoggingBad.swift"/>
|
||||
<p>
|
||||
Instead, you should encrypt or obfuscate the credentials, or omit them entirely:
|
||||
</p>
|
||||
<sample src="CleartextLoggingGood.swift"/>
|
||||
</example>
|
||||
|
||||
<references>
|
||||
|
||||
<li>M. Dowd, J. McDonald and J. Schuhm, <i>The Art of Software Security Assessment</i>, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.</li>
|
||||
<li>M. Howard and D. LeBlanc, <i>Writing Secure Code</i>, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.</li>
|
||||
<li>OWASP: <a href="https://www.owasp.org/index.php/Password_Plaintext_Storage">Password Plaintext Storage</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
24
swift/ql/src/queries/Security/CWE-312/CleartextLogging.ql
Normal file
24
swift/ql/src/queries/Security/CWE-312/CleartextLogging.ql
Normal file
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @name Cleartext logging of sensitive information
|
||||
* @description Logging sensitive information in plaintext can
|
||||
* expose it to an attacker.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 7.5
|
||||
* @precision high
|
||||
* @id swift/clear-text-logging
|
||||
* @tags security
|
||||
* external/cwe/cwe-312
|
||||
* external/cwe/cwe-359
|
||||
* external/cwe/cwe-532
|
||||
*/
|
||||
|
||||
import swift
|
||||
import codeql.swift.dataflow.DataFlow
|
||||
import codeql.swift.security.CleartextLoggingQuery
|
||||
import DataFlow::PathGraph
|
||||
|
||||
from DataFlow::PathNode src, DataFlow::PathNode sink
|
||||
where any(CleartextLoggingConfiguration c).hasFlowPath(src, sink)
|
||||
select sink.getNode(), src, sink, "This $@ is written to a log file.", src.getNode(),
|
||||
"potentially sensitive information"
|
||||
@@ -0,0 +1,2 @@
|
||||
let password = "P@ssw0rd"
|
||||
NSLog("User password changed to \(password)")
|
||||
@@ -0,0 +1,2 @@
|
||||
let password = "P@ssw0rd"
|
||||
NSLog("User password changed")
|
||||
@@ -0,0 +1,24 @@
|
||||
import swift
|
||||
import codeql.swift.dataflow.DataFlow
|
||||
import codeql.swift.security.CleartextLoggingQuery
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class CleartextLogging extends InlineExpectationsTest {
|
||||
CleartextLogging() { this = "CleartextLogging" }
|
||||
|
||||
override string getARelevantTag() { result = "hasCleartextLogging" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(
|
||||
CleartextLoggingConfiguration config, DataFlow::Node source, DataFlow::Node sink,
|
||||
Expr sinkExpr
|
||||
|
|
||||
config.hasFlow(source, sink) and
|
||||
sinkExpr = sink.asExpr() and
|
||||
location = sinkExpr.getLocation() and
|
||||
element = sinkExpr.toString() and
|
||||
tag = "hasCleartextLogging" and
|
||||
value = source.asExpr().getLocation().getStartLine().toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
// --- stubs ---
|
||||
|
||||
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) {}
|
||||
|
||||
}
|
||||
|
||||
// --- tests ---
|
||||
|
||||
func test1(password: String, passwordHash : String) {
|
||||
print(password) // $ MISSING: hasCleartextLogging=87
|
||||
print(password, separator: "") // $ MISSING: $ hasCleartextLogging=88
|
||||
print("", separator: password) // $ hasCleartextLogging=89
|
||||
print(password, separator: "", terminator: "") // $ MISSING: hasCleartextLogging=90
|
||||
print("", separator: password, terminator: "") // $ hasCleartextLogging=91
|
||||
print("", separator: "", terminator: password) // $ hasCleartextLogging=92
|
||||
print(passwordHash) // Safe
|
||||
|
||||
NSLog(password) // $ hasCleartextLogging=95
|
||||
NSLog("%@", password as! CVarArg) // $ MISSING: hasCleartextLogging=96
|
||||
NSLog("%@ %@", "" as! CVarArg, password as! CVarArg) // $ MISSING: hasCleartextLogging=97
|
||||
NSLog("\(password)") // $ hasCleartextLogging=98
|
||||
NSLogv("%@", getVaList([password as! CVarArg])) // $ MISSING: hasCleartextLogging=99
|
||||
NSLogv("%@ %@", getVaList(["" as! CVarArg, password as! CVarArg])) // $ MISSING: hasCleartextLogging=100
|
||||
NSLog(passwordHash) // SAfe
|
||||
NSLogv("%@", getVaList([passwordHash as! CVarArg])) // 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)") // Safe
|
||||
log.log("\(password, privacy: .auto)") // Safe
|
||||
log.log("\(password, privacy: .private)") // Safe
|
||||
log.log("\(password, privacy: .public)") // $ MISSING: hasCleartextLogging=110
|
||||
log.log("\(passwordHash, privacy: .public)") // Safe
|
||||
log.log("\(password, privacy: .sensitive)") // Safe
|
||||
log.log("\(bankAccount)") // $ MISSING: hasCleartextLogging=113
|
||||
log.log("\(bankAccount, privacy: .auto)") // $ MISSING: hasCleartextLogging=114
|
||||
log.log("\(bankAccount, privacy: .private)") // Safe
|
||||
log.log("\(bankAccount, privacy: .public)") // $ MISSING: hasCleartextLogging=116
|
||||
log.log("\(bankAccount, privacy: .sensitive)") // Safe
|
||||
log.log(level: .default, "\(password, privacy: .public)") // $ MISSING: hasCleartextLogging=118
|
||||
log.trace("\(password, privacy: .public)") // $ MISSING: hasCleartextLogging=119
|
||||
log.trace("\(passwordHash, privacy: .public)") // Safe
|
||||
log.debug("\(password, privacy: .public)") // $ MISSING: hasCleartextLogging=121
|
||||
log.debug("\(passwordHash, privacy: .public)") // Safe
|
||||
log.info("\(password, privacy: .public)") // $ MISSING: hasCleartextLogging=123
|
||||
log.info("\(passwordHash, privacy: .public)") // Safe
|
||||
log.notice("\(password, privacy: .public)") // $ MISSING: hasCleartextLogging=125
|
||||
log.notice("\(passwordHash, privacy: .public)") // Safe
|
||||
log.warning("\(password, privacy: .public)") // $ MISSING: hasCleartextLogging=127
|
||||
log.warning("\(passwordHash, privacy: .public)") // Safe
|
||||
log.error("\(password, privacy: .public)") // $ MISSING: hasCleartextLogging=129
|
||||
log.error("\(passwordHash, privacy: .public)") // Safe
|
||||
log.critical("\(password, privacy: .public)") // $ MISSING: hasCleartextLogging=131
|
||||
log.critical("\(passwordHash, privacy: .public)") // Safe
|
||||
log.fault("\(password, privacy: .public)") // $ MISSING: hasCleartextLogging=133
|
||||
log.fault("\(passwordHash, privacy: .public)") // Safe
|
||||
}
|
||||
|
||||
class MyClass {
|
||||
var harmless = "abc"
|
||||
var password = "123"
|
||||
}
|
||||
|
||||
func getPassword() -> String { return "" }
|
||||
func doSomething(password: String) { }
|
||||
|
||||
func test3(x: String) {
|
||||
// alternative evidence of sensitivity...
|
||||
|
||||
NSLog(x) // $ MISSING: hasCleartextLogging=148
|
||||
doSomething(password: x);
|
||||
NSLog(x) // $ hasCleartextLogging=149
|
||||
|
||||
let y = getPassword();
|
||||
NSLog(y) // $ hasCleartextLogging=152
|
||||
|
||||
let z = MyClass()
|
||||
NSLog(z.harmless) // Safe
|
||||
NSLog(z.password) // $ hasCleartextLogging=157
|
||||
}
|
||||
Reference in New Issue
Block a user