Cleartext Transmission of Sensitive Information
ID |
swift.sensitive_information_cleartext_transmission |
Severity |
low |
Resource |
Information Leak |
Language |
Swift |
Tags |
CWE:319, MASVS:NETWORK-1, MASWE:0050, NIST.SP.800-53, OWASP:2021:A2, PCI-DSS:4.1 |
Description
Transmitting sensitive data over unencrypted network connections exposes it to interception by attackers. When applications send passwords, authentication tokens, credit card numbers, personal health information, or other sensitive data over HTTP (cleartext) connections, attackers on the same network can capture and read this information.
This rule detects when sensitive information is transmitted without encryption, specifically when:
-
The transmitted data contains sensitive keywords (password, token, creditCard, ssn, etc.)
-
The connection uses HTTP instead of HTTPS
-
No encryption is applied to the data before transmission
Rationale
Network traffic transmitted without encryption is vulnerable to several attack vectors:
-
Man-in-the-Middle (MITM) Attacks:
import Foundation
class VulnerableAuthService {
// VULNERABLE: Sending password over HTTP
func login(username: String, password: String) {
let loginURL = "http://api.example.com/login" // HTTP - not HTTPS!
guard let url = URL(string: loginURL) else { return }
var request = URLRequest(url: url)
request.httpMethod = "POST"
// FLAW: Sensitive password transmitted in cleartext
let body = "username=\(username)&password=\(password)"
request.httpBody = body.data(using: .utf8)
// ISSUE: Password can be intercepted on the network
URLSession.shared.dataTask(with: request) { data, response, error in
// Handle response
}.resume()
}
// VULNERABLE: API token in HTTP request
func fetchUserData(apiToken: String) {
let endpoint = "http://api.example.com/user/profile"
guard let url = URL(string: endpoint) else { return }
var request = URLRequest(url: url)
// FLAW: API token in Authorization header over HTTP
request.addValue("Bearer \(apiToken)", forHTTPHeaderField: "Authorization")
URLSession.shared.dataTask(with: request) { data, response, error in
// Token exposed in cleartext
}.resume()
}
// VULNERABLE: Credit card data over HTTP
func submitPayment(creditCardNumber: String, cvv: String) {
let paymentURL = "http://payments.example.com/process"
guard let url = URL(string: paymentURL) else { return }
let paymentData = [
"cardNumber": creditCardNumber, // FLAW: PCI-DSS violation
"cvv": cvv
]
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = try? JSONSerialization.data(withJSONObject: paymentData)
// ISSUE: Credit card data transmitted in cleartext
URLSession.shared.dataTask(with: request) { data, response, error in
// Payment info exposed
}.resume()
}
}
-
Alamofire with HTTP:
import Alamofire
class AlamofireVulnerableService {
// VULNERABLE: Alamofire request with sensitive data over HTTP
func authenticateUser(email: String, password: String) {
let loginEndpoint = "http://api.example.com/auth/login" // HTTP!
let parameters: [String: String] = [
"email": email,
"password": password // FLAW: Password in HTTP POST
]
// ISSUE: Alamofire sends password over unencrypted connection
AF.request(loginEndpoint, method: .post, parameters: parameters).response { response in
// Password exposed in network traffic
}
}
// VULNERABLE: API key in HTTP headers
func fetchData(apiKey: String) {
let endpoint = "http://api.example.com/data"
let headers: HTTPHeaders = [
"X-API-Key": apiKey // FLAW: API key over HTTP
]
AF.request(endpoint, headers: headers).responseJSON { response in
// API key can be captured
}
}
// VULNERABLE: SSN transmitted over HTTP
func updateProfile(ssn: String) {
let profileURL = "http://api.example.com/profile"
AF.request(profileURL, method: .put, parameters: ["ssn": ssn]).response { response in
// ISSUE: Social Security Number in cleartext
}
}
}
-
Vapor Server-Side HTTP Client:
import Vapor
class VaporVulnerableClient {
// VULNERABLE: Vapor client sending sensitive data over HTTP
func sendWebhook(req: Request, authToken: String) async throws {
let webhookURL = "http://partner-api.com/webhook" // HTTP!
let payload = [
"token": authToken, // FLAW: Auth token over HTTP
"event": "user_created"
]
// ISSUE: Sending auth token in cleartext
let response = try await req.client.post(URI(string: webhookURL)) { webhookReq in
try webhookReq.content.encode(payload)
}
}
// VULNERABLE: Health data over HTTP
func syncHealthData(req: Request, healthRecords: [String: Any]) async throws {
let syncURL = "http://health-sync.example.com/upload"
// FLAW: PHI (Protected Health Information) over HTTP - HIPAA violation
let response = try await req.client.post(URI(string: syncURL)) { syncReq in
try syncReq.content.encode(healthRecords)
}
}
}
-
Network Framework (NWConnection):
import Network
class NetworkConnectionService {
// VULNERABLE: NWConnection without TLS
func sendData(password: String) {
// HTTP endpoint (port 80) without TLS
let endpoint = NWEndpoint.hostPort(host: "api.example.com", port: 80)
// FLAW: Parameters without TLS
let parameters = NWParameters.tcp
let connection = NWConnection(to: endpoint, using: parameters)
connection.start(queue: .global())
// ISSUE: Sending password without encryption
let data = "password=\(password)".data(using: .utf8)!
connection.send(content: data, completion: .contentProcessed { error in
// Password transmitted in cleartext
})
}
// VULNERABLE: Token over insecure connection
func authenticateWithToken(authToken: String) {
let host = NWEndpoint.Host("api.example.com")
let port = NWEndpoint.Port(rawValue: 8080)!
let endpoint = NWEndpoint.hostPort(host: host, port: port)
// No TLS configured
let connection = NWConnection(to: endpoint, using: .tcp)
connection.start(queue: .main)
// FLAW: Auth token sent without encryption
let tokenData = "Authorization: Bearer \(authToken)".data(using: .utf8)!
connection.send(content: tokenData, completion: .idempotent)
}
}
These examples demonstrate cleartext transmission vulnerabilities:
-
HTTP URLs: Using
http://instead ofhttps://protocol -
Sensitive parameters: Passwords, tokens, API keys in request bodies or headers
-
Financial data: Credit card numbers, CVV codes transmitted without encryption
-
Personal data: SSN, health records, location data over insecure connections
-
No TLS configuration: TCP connections without TLS in Network framework
Security Impact:
-
Passive eavesdropping: Attackers on the same network (WiFi, ISP) can capture traffic
-
Man-in-the-Middle: Attackers can intercept and modify requests/responses
-
Session hijacking: Authentication tokens stolen from cleartext traffic
-
Credential theft: Usernames and passwords captured from login requests
-
Compliance violations: PCI-DSS, HIPAA, GDPR require encryption for sensitive data
Remediation
Always use HTTPS (TLS/SSL) for transmitting sensitive data. iOS and macOS enforce App Transport Security (ATS) by default, which blocks cleartext HTTP connections, but this can be disabled in Info.plist (which should be avoided).
Use HTTPS URLs
-
FIXED: URLSession with HTTPS:
import Foundation
class SecureAuthService {
// FIXED: Using HTTPS instead of HTTP
func login(username: String, password: String) {
let loginURL = "https://api.example.com/login" // HTTPS!
guard let url = URL(string: loginURL) else { return }
var request = URLRequest(url: url)
// ... rest of code
}
// FIXED: API token over HTTPS
func fetchUserData(apiToken: String) {
let endpoint = "https://api.example.com/user/profile" // HTTPS
guard let url = URL(string: endpoint) else { return }
var request = URLRequest(url: url)
// ... rest of code
}
// FIXED: URLSession configuration with TLS requirements
func configureSecureSession() -> URLSession {
let config = URLSessionConfiguration.default
// Enforce TLS 1.2 minimum
config.tlsMinimumSupportedProtocolVersion = .TLSv12
return URLSession(configuration: config)
}
}
-
FIXED: Alamofire with HTTPS:
import Alamofire
class SecureAlamofireService {
// FIXED: HTTPS endpoint
func authenticateUser(email: String, password: String) {
let loginEndpoint = "https://api.example.com/auth/login" // HTTPS
// ... rest of code
}
// FIXED: Certificate pinning for additional security
func setupCertificatePinning() -> Session {
let evaluators = [
"api.example.com": PinnedCertificatesTrustEvaluator()
]
let serverTrustManager = ServerTrustManager(evaluators: evaluators)
return Session(serverTrustManager: serverTrustManager)
}
// FIXED: Using pinned session
func secureRequest(apiKey: String, session: Session) {
let endpoint = "https://api.example.com/data"
// ... rest of code
}
}
-
FIXED: Vapor with HTTPS:
import Vapor
class SecureVaporClient {
// FIXED: HTTPS URL
func sendWebhook(req: Request, authToken: String) async throws {
let webhookURL = "https://partner-api.com/webhook" // HTTPS
// ... rest of code
}
// FIXED: Configure HTTP client with TLS
func configureSecureClient(app: Application) {
app.http.client.configuration.tlsConfiguration = .makeClientConfiguration()
}
}
-
FIXED: Network Framework with TLS:
import Network
class SecureNetworkService {
// FIXED: NWConnection with TLS
func sendDataSecurely(password: String) {
let endpoint = NWEndpoint.hostPort(host: "api.example.com", port: 443)
// Use TLS parameters
let tlsOptions = NWProtocolTLS.Options()
let parameters = NWParameters(tls: tlsOptions)
let connection = NWConnection(to: endpoint, using: parameters)
// ... Rest of code the same
}
// FIXED: Custom TLS configuration
func configureCustomTLS() -> NWParameters {
let tlsOptions = NWProtocolTLS.Options()
// Configure TLS settings via sec_protocol_options
sec_protocol_options_set_min_tls_protocol_version(
tlsOptions.securityProtocolOptions,
.TLSv12 // Minimum TLS 1.2
)
return NWParameters(tls: tlsOptions)
}
}
Encrypt Sensitive Data Before Transmission
If you must use HTTP or have additional security requirements, encrypt sensitive data before transmission:
import CryptoKit
class EncryptedTransmission {
// Encrypt sensitive data before HTTP transmission
func sendEncryptedPassword(password: String, encryptionKey: SymmetricKey) {
// Encrypt password
let passwordData = password.data(using: .utf8)!
let sealedBox = try! AES.GCM.seal(passwordData, using: encryptionKey)
let encryptedData = sealedBox.combined!
// Can now transmit encrypted data (though HTTPS is still recommended)
let loginURL = "https://api.example.com/login"
guard let url = URL(string: loginURL) else { return }
// ... rest of code
}
}
App Transport Security (ATS)
iOS and macOS enforce App Transport Security by default, which requires HTTPS. Never disable ATS unless absolutely necessary (and only for specific domains).
Key Prevention Strategies
-
Always use HTTPS - Replace all
http://URLs withhttps:// -
Enforce TLS 1.2 or newer - Configure URLSession and network libraries to reject weak TLS versions.
-
Certificate pinning - Implement certificate or public key pinning for critical connections.
-
Respect ATS - Keep App Transport Security enabled, avoid
NSAllowsArbitraryLoads -
Encrypt sensitive fields - Use CryptoKit to encrypt sensitive data before transmission (defense in depth)
-
Audit Info.plist - Review and minimize ATS exceptions to the HTTPS enforcing policy.
-
Use secure default configurations - Prefer framework defaults that enforce HTTPS
Configuration
This detector can be configured to:
-
Customize which data categories are considered sensitive (via
sensitiveKinds). -
Define encryption function names that neutralize the issue.
Example configuration in swift.sensitive_information_cleartext_transmission.yml:
properties:
sensitiveKinds:
- access_control
- crypto
- financial
- health
- location
- personal_identifiable_information
encryptionFunctions:
- encrypt
- seal
- encryptData
References
-
CWE-319: Cleartext Transmission of Sensitive Information.
-
MASWE-0050: Cleartext Traffic.
-
OWASP Mobile Top 10: M5 - Insecure Communication.