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 - Avoid Shell Execution for External Commands
**Vulnerability:** Invoking commands like `docker system prune` using a shell wrapper (`/bin/bash -c "..."`) instead of executing the binary directly exposes the application to command injection vulnerabilities, especially if any part of the command were to become dynamic. Using shell wrappers also complicates error handling and securely replicating shell features like redirection.
**Learning:** Shell redirections like `2>&1` in shell commands can be securely replicated natively in Swift's Foundation `Process` without the need for an intermediate shell. This is done by assigning the identical `Pipe()` instance to both `process.standardOutput` and `process.standardError`. Using `URL(fileURLWithPath: "/usr/bin/env")` as the executable URL and passing the tool name as the first argument in `process.arguments` allows executing commands cleanly and directly while still respecting the `PATH` environment variable.
**Prevention:** Always prefer direct binary execution via `Process` in Swift instead of using `/bin/bash -c` or similar shell wrappers. Pass all dynamic inputs explicitly as elements in the `process.arguments` array. If shell-specific features like output redirection are needed, implement them securely using the native `Process` configuration options rather than relying on shell syntax.
4 changes: 2 additions & 2 deletions Sources/Cacheout/ViewModels/CacheoutViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ class CacheoutViewModel: ObservableObject {

let process = Process()
let pipe = Pipe()
process.executableURL = URL(fileURLWithPath: "/bin/bash")
process.arguments = ["-c", "docker system prune -f 2>&1"]
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
process.arguments = ["docker", "system", "prune", "-f"]
process.standardOutput = pipe
process.standardError = pipe
process.environment = [
Expand Down