diff --git a/.jules/sentinel.md b/.jules/sentinel.md index e19da74..7f6136a 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -12,3 +12,7 @@ **Vulnerability:** A process can block (deadlock) when its stdout/stderr pipe fills before the parent reads it, because the child blocks on `write()` while the parent blocks on `waitUntilExit()`. **Learning:** `pipe.fileHandleForReading.readDataToEndOfFile()` after `process.waitUntilExit()` is the deadlock pattern. Default macOS pipe buffer is ~64KB. **Prevention:** Read the pipe before/concurrently-with waiting for exit. The simplest pattern is to perform the read inside the same background queue that calls `waitUntilExit()`, capturing the bytes for the caller to use after the dispatch group resolves. +## 2024-05-24 - Enforce HTTPS for Webhooks +**Vulnerability:** Webhook configuration allowed 'http' schemes, leading to potential unencrypted transmission of sensitive daemon alerts. +**Learning:** Webhook alerters and configuration parsers must strictly enforce HTTPS to ensure that sensitive system data and telemetry are not transmitted over unencrypted channels. +**Prevention:** Always validate URL schemes in both configuration parsing and dynamic validation logic, explicitly rejecting 'http' in favor of 'https' for any external data transmission. diff --git a/Sources/Cacheout/Headless/StatusSocket.swift b/Sources/Cacheout/Headless/StatusSocket.swift index 12c516e..6914333 100644 --- a/Sources/Cacheout/Headless/StatusSocket.swift +++ b/Sources/Cacheout/Headless/StatusSocket.swift @@ -708,8 +708,8 @@ public enum AutopilotConfigValidator { if let urlStr = webhook["url"] as? String { if let url = URL(string: urlStr) { let scheme = url.scheme?.lowercased() ?? "" - if scheme != "http" && scheme != "https" { - errors.append("webhook: url must use http or https scheme, got '\(scheme)'") + if scheme != "https" { + errors.append("webhook: url must use https scheme, got '\(scheme)'") } if url.host == nil || url.host?.isEmpty == true { errors.append("webhook: url must be an absolute URL with a host") diff --git a/Sources/Cacheout/Headless/WebhookAlerter.swift b/Sources/Cacheout/Headless/WebhookAlerter.swift index 8fa8a8e..1ddfb94 100644 --- a/Sources/Cacheout/Headless/WebhookAlerter.swift +++ b/Sources/Cacheout/Headless/WebhookAlerter.swift @@ -336,7 +336,8 @@ extension WebhookAlerter.WebhookConfig { public static func parse(from json: [String: Any]) -> WebhookAlerter.WebhookConfig? { guard let webhook = json["webhook"] as? [String: Any], let urlStr = webhook["url"] as? String, - let url = URL(string: urlStr) else { + let url = URL(string: urlStr), + url.scheme?.lowercased() == "https" else { return nil } let format = webhook["format"] as? String ?? "generic"