VNX-SWIFT-004 – Swift TLS Certificate Validation Disabled in URLSession or Alamofire
Overview
This rule reports Swift code that accepts a TLS server certificate without validating it:
URLCredential(trust:)built in a function that never evaluates or pins the trust before it (noSecTrustEvaluateWithError/SecTrustEvaluate,evaluator.evaluate(...), certificate or public-key comparison, or call to a validate/verify/check/pin helper). This is how aURLSessionorNSURLConnectionauth-challenge delegate trusts every certificate. A host-name comparison is not validation.- Alamofire
DisabledTrustEvaluator()/DisabledEvaluator()and the Alamofire 4ServerTrustPolicy.disableEvaluation. kCFStreamSSLValidatesCertificateChainset to false on a stream.NSURLRequest.setAllowsAnyHTTPSCertificate(true, forHost:).- A
sec_protocol_options_set_verify_blockwhose block completes withtruewithout evaluating the trust.
It does not report URLCredential(trust:) after the trust was evaluated or pinned, URLCredential(user:password:), .performDefaultHandling, pinned or default Alamofire evaluators, the evaluator class declarations, string literals, comments and test files.
This maps to CWE-295: Improper Certificate Validation.
Severity: High | CWE: CWE-295 – Improper Certificate Validation
Why This Matters
Disabling TLS certificate validation eliminates the only mechanism that proves the server the application is communicating with is who it claims to be. On any untrusted network — public Wi-Fi, hotel networks, carrier networks with traffic inspection appliances — an attacker can perform a man-in-the-middle (MITM) attack by presenting their own certificate to the client. With validation disabled, the client accepts this certificate and the attacker receives all traffic in cleartext: credentials, session tokens, payment data, health information, and any other sensitive content.
This pattern is extremely common in development codebases. Developers disable validation to work with self-signed certificates on local test servers and forget to re-enable it before shipping. Tools such as Burp Suite and Charles Proxy are explicitly designed to exploit this class of vulnerability to intercept mobile app traffic, and penetration testers routinely discover it in production applications.
Certificate pinning — associating the server’s specific public key with the application — provides an additional layer of defence beyond standard chain validation. Even if an attacker obtains a certificate from a trusted CA, pinning will reject it unless the public key matches the pinned value.
What Gets Flagged
// FLAGGED: URLCredential(trust:) unconditionally accepts any certificate
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
let credential = URLCredential(trust: challenge.protectionSpace.serverTrust!) // FLAGGED
completionHandler(.useCredential, credential)
}
// FLAGGED: completion handler accepts credential without verifying serverTrust
func urlSession(_ session: URLSession,
task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
// FLAGGED: Starscream WebSocket accepting any or self-signed certificates
socket.disableSSLCertValidation = true
let pinner = FoundationSecurity(allowSelfSigned: true)
// FLAGGED: Alamofire server trust evaluation disabled
let manager = Session(serverTrustManager: ServerTrustManager(evaluators: [
"api.example.com": DisabledTrustEvaluator() // FLAGGED
]))
Remediation
Perform proper server trust evaluation in
URLSessionauthentication challenge delegates. Validate the certificate chain against system-trusted roots before callingcompletionHandler(.useCredential, ...).// SAFE: proper server trust evaluation func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust, let serverTrust = challenge.protectionSpace.serverTrust else { completionHandler(.cancelAuthenticationChallenge, nil) return } // Evaluate the server trust using system policy var error: CFError? let isValid = SecTrustEvaluateWithError(serverTrust, &error) if isValid { completionHandler(.useCredential, URLCredential(trust: serverTrust)) } else { completionHandler(.cancelAuthenticationChallenge, nil) } }Use Alamofire’s
PinnedCertificatesTrustEvaluatororPublicKeysTrustEvaluatorfor certificate pinning. This validates both the chain and the specific certificate or key.// SAFE: Alamofire with certificate pinning let evaluators: [String: ServerTrustEvaluating] = [ "api.example.com": PinnedCertificatesTrustEvaluator( certificates: Bundle.main.af.certificates, acceptSelfSignedCertificates: false, performDefaultValidation: true, validateHost: true ) ] let session = Session(serverTrustManager: ServerTrustManager(evaluators: evaluators))Remove test-only validation bypasses before merging to main. Use build flags or separate test configurations so that certificate validation bypasses used for local development are never included in production builds.
// SAFE: bypass only in debug builds #if DEBUG let evaluators: [String: ServerTrustEvaluating] = [ "localhost": DisabledTrustEvaluator() ] #else let evaluators: [String: ServerTrustEvaluating] = [ "api.example.com": PinnedCertificatesTrustEvaluator() ] #endifEnable App Transport Security (ATS). Ensure
NSAllowsArbitraryLoadsis not set totrueinInfo.plist. ATS enforces minimum TLS requirements at the OS level as an additional safety net.
References
- CWE-295: Improper Certificate Validation
- OWASP Mobile Security Testing Guide – MSTG-NETWORK-3 (Certificate Validation)
- Apple – Preventing Insecure Network Connections (App Transport Security)
- Apple – SecTrustEvaluateWithError
- Alamofire – Security Documentation
- CAPEC-94: Adversary in the Middle (CAPEC-94)
- MITRE ATT&CK T1557 – Adversary-in-the-Middle