Description
When Process launches a shell with user input after -c, the shell interprets that input as command syntax, potentially allowing arbitrary command execution. Even without a shell, allowing a user to choose the executable path or control a program's options can cause unintended operations.
Potential impact
- Arbitrary command execution.
- Reading, deleting, or exfiltrating files.
- Compromise of privileges on a server or developer workstation.
Remediation
- Avoid shell execution through
-cand use a fixed executable path. - Pass arguments separately through
Process.argumentsand validate each value against an allow-list. - If constructing a shell string is unavoidable, use a proven escaping function and run with the least possible privileges.
Examples
Before
swift
let command = readLine()!
let task = Process()
task.launchPath = "/bin/sh"
task.arguments = ["-c", command]
After
swift
import Foundation
func runGitStatus(for path: String) throws {
let task = Process()
task.executableURL = URL(fileURLWithPath: "/usr/bin/git")
task.arguments = ["status", "--", path]
try task.run()
task.waitUntilExit()
}
Explanation:
- Before: Running the process with this configuration interprets the entire input as a shell command.
- After: The executable and subcommand are fixed, and the user value follows
--, preventing shell interpretation and option injection.