6 stable releases
Uses new Rust 2024
| 1.2.0 | Dec 25, 2025 |
|---|---|
| 1.1.2 | Dec 25, 2025 |
| 1.1.1 | Dec 24, 2025 |
| 1.0.1 | Dec 24, 2025 |
| 1.0.0 | Dec 23, 2025 |
#197 in Authentication
50 downloads per month
Used in quincy-gui
51KB
764 lines
privesc
Cross-platform privilege escalation for Rust.
Run commands with elevated privileges on macOS, Linux, and Windows.
Usage
There is explicit validation for the program parameter to ensure that it is an absolute path to an executable file.
This is done in order to ensure that the target executable has not been tampered with or is not a symlink to a malicious binary (PATH hijacking etc.)
use privesc::PrivilegedCommand;
fn main() -> privesc::Result<()> {
let output = PrivilegedCommand::new("/usr/bin/cat")
.arg("/etc/shadow")
.run()?;
if output.success() {
if let Some(content) = output.stdout_str() {
println!("{content}");
}
}
Ok(())
}
With all options:
use privesc::PrivilegedCommand;
let output = PrivilegedCommand::new("/usr/bin/cat")
.args(["/etc/shadow", "/etc/passwd"])
.gui(true)
.prompt("Reading protected files")
.run()?;
Spawning without blocking
Use spawn() to start a privileged process and continue working while it runs:
use privesc::PrivilegedCommand;
fn main() -> privesc::Result<()> {
let mut child = PrivilegedCommand::new("/usr/bin/long-task")
.spawn()?;
if let Some(id) = child.id() {
println!("Process started with ID: {id}");
}
// Do other work while the process runs...
// Check if done without blocking
if let Some(status) = child.try_wait()? {
println!("Already finished: {status}");
}
// Block until completion
let output = child.wait()?;
println!("Exit status: {}", output.status);
Ok(())
}
Platform Behavior
| Platform | GUI mode | CLI mode | Output capture |
|---|---|---|---|
| macOS | AppleScript dialog | sudo |
Yes |
| Linux | pkexec |
sudo |
Yes |
| Windows | UAC prompt | UAC prompt | No |
macOS
CLI mode (sudo): Arguments are passed directly via Rust's Command::args(), which uses execve under the hood. No shell is involved — arguments are passed as-is to the target program regardless of special characters.
GUI mode (osascript): Arguments flow through two stages:
- Rust → osascript: Uses
Command::args()(no shell, safe) - AppleScript → target: Uses
quoted form ofto escape each argument before passing todo shell script
AppleScript's quoted form of wraps arguments in single quotes and escapes embedded single quotes as '\''. This prevents shell interpretation of $, backticks, spaces, and other metacharacters.
Linux
CLI mode (sudo): Arguments are passed directly via Rust's Command::args(), which uses execve under the hood. No shell is involved — arguments are passed as-is to the target program regardless of special characters.
GUI mode (pkexec): Same as CLI mode (sudo)
Windows
CLI mode (UAC via ShellExecuteExW): The Windows API takes arguments as a single string, not an array. This library implements custom escaping following Windows command-line parsing conventions:
- Regular executables: Arguments are escaped per
CommandLineToArgvWrules (quotes, backslashes) - Batch files (
.bat/.cmd): Additional escaping prevents%VAR%environment variable expansion and related injection vectors (addresses CVE-2024-24576 class vulnerabilities)
GUI mode (runas): Same as CLI mode (ShellExecuteExW)
Dependencies
~0.2–29MB
~472K SLoC