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
@@ -0,0 +1,4 @@
## 2024-05-24 - Process execution via shell wrapper
**Vulnerability:** Execution of command `docker system prune -f 2>&1` via `/bin/bash -c` in `CacheoutViewModel.swift`. Although there wasn't dynamic input here, using shell wrappers is a systemic risk for command injection in Swift.
**Learning:** Shell redirections like `2>&1` can be replicated securely in Swift by assigning the same `Pipe()` instance to both `process.standardOutput` and `process.standardError` without needing `/bin/bash`.
**Prevention:** Avoid shell wrappers (`/bin/bash -c`). Use direct executable invocation (e.g., `/usr/bin/env` with binary name) with an explicitly defined `arguments` array. Set stdout and stderr to the same `Pipe()` instance to capture combined output instead of relying on shell operators.
6 changes: 4 additions & 2 deletions Sources/Cacheout/ViewModels/CacheoutViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,10 @@ class CacheoutViewModel: ObservableObject {

let process = Process()
let pipe = Pipe()
process.executableURL = URL(fileURLWithPath: "/bin/bash")
process.arguments = ["-c", "docker system prune -f 2>&1"]
// Run direct binary without shell wrapper to avoid command injection risks.
// The previous 2>&1 redirection is handled by assigning `pipe` to both stdout/stderr.
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
process.arguments = ["docker", "system", "prune", "-f"]
process.standardOutput = pipe
process.standardError = pipe
process.environment = [
Expand Down