Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .Jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@
**Vulnerability:** The application was falling back to storing OBS passwords as plaintext strings inside exported/saved JSON models (`Macro.swift` and `SystemCommand.swift`) if saving to the macOS Keychain failed.
**Learning:** Saving secrets to unencrypted formats simply because secure storage fails is a critical anti-pattern known as "failing open" that results in data exposure.
**Prevention:** Always fail securely. If secure storage operations fail, discard the sensitive credential in memory rather than writing it insecurely to disk, even if it requires the user to re-authenticate later.
## 2026-06-26 - [Process Pipe Buffer Deadlock]
**Vulnerability:** Parent processes executing `Process()` (NSTask) with piped standard output/error were deadlocking if the child output exceeded the OS pipe buffer size (~64KB). The parent process called `waitUntilExit()` before reading the output, causing a classic IPC deadlock.
**Learning:** This is a DoS risk if an attacker can control or pad the output of commands executed by the application.
**Prevention:** Always read all data from `Pipe()` objects (e.g., using `readDataToEndOfFile()`) *before* calling `process.waitUntilExit()`.
5 changes: 3 additions & 2 deletions TriggerKit/Sources/TriggerKitRuntime/AutomationExecutor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -354,9 +354,10 @@ public final class AutomationExecutor {
} catch {
return .failure("\(name) launch failed: \(error.localizedDescription)")
}
process.waitUntilExit()

let data = pipe.fileHandleForReading.readDataToEndOfFile()
process.waitUntilExit()

let output = String(data: data, encoding: .utf8)?
.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""

Expand Down Expand Up @@ -731,11 +732,11 @@ private final class ShellCommandRunner: @unchecked Sendable {
pgrep.standardError = FileHandle.nullDevice
do {
try pgrep.run()
pgrep.waitUntilExit()
} catch {
return []
}
let data = pipe.fileHandleForReading.readDataToEndOfFile()
pgrep.waitUntilExit()
let output = String(data: data, encoding: .utf8) ?? ""
return output
.split(whereSeparator: \.isNewline)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1405,10 +1405,11 @@ final class UniversalControlMouseRelay: @unchecked Sendable {
NSLog("[UCMouseRelay] Could not run tailscale status: %@", String(describing: error))
return []
}

let data = pipe.fileHandleForReading.readDataToEndOfFile()
process.waitUntilExit()
guard process.terminationStatus == 0 else { return [] }

let data = pipe.fileHandleForReading.readDataToEndOfFile()
guard let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let peers = object["Peer"] as? [String: Any] else {
return []
Expand Down
Loading