Command Injection in Rocket with Bearer Tokens
Command Injection in Rocket with Bearer Tokens — how this specific combination creates or exposes the vulnerability
Command Injection occurs when an API endpoint passes untrusted input directly to a system shell or process builder. In Rocket, a common pattern is to read an Authorization header containing a Bearer Token and use it as part of a command or script execution flow. Because the token is treated as user-controlled data, an attacker can inject shell metacharacters to alter command behavior.
Consider a Rocket handler that receives a Bearer Token and passes it to a system command without validation:
#[macro_use] extern crate rocket;
use rocket::http::Status;
use rocket::request::Request;
#[get("/run/")]
fn run_command(cmd: String, auth: Option<rocket::http::Header>) -> String {
if let Some(header) = auth {
if header.name == "Authorization" {
let token = header.value.strip_prefix("Bearer ").unwrap_or("");
// Unsafe: token used directly in command construction
let output = std::process::Command::new("sh")
.arg("-c")
.arg(format!("echo Token: {} && {}", token, cmd))
.output()
.expect("failed to execute process");
return String::from_utf8_lossy(&output.stdout).to_string();
}
}
Status::Unauthorized.into()
}
If an attacker sends cmd as ls and the Bearer Token as mysecret|id, the shell command becomes echo Token: mysecret|id && ls, causing unintended command execution and information disclosure. This is a classic Command Injection vector amplified by the presence of a Bearer Token as uncontrolled input.
Rocket applications often integrate with external services using tokens. When those tokens are forwarded to subprocesses or scripts—such as via std::process::Command, duct, or OS helpers—special characters like ;, &, |, $(), or backticks can change command semantics. Even if the token is obtained from a trusted source (e.g., a header), treating it as safe is a mistake. Attackers can leverage weak input validation or missing allowlists to pivot from authentication context to arbitrary command execution.
Additionally, logging or error messages that include the Bearer Token alongside injected commands can compound risk by exposing sensitive data in logs or responses. The combination of Rocket’s routing and handler flexibility with Bearer Token usage in command construction creates scenarios where injection flaws are subtle yet impactful.
Bearer Tokens-Specific Remediation in Rocket — concrete code fixes
Remediation centers on avoiding shell invocation and strictly validating or encoding any data that may reach the command layer. The safest approach is to bypass the shell entirely and use argument vectors directly.
Instead of using sh -c, use std::process::Command with explicit arguments:
#[macro_use] extern crate rocket;
use rocket::http::Status;
use rocket::request::Request;
#[get("/run/")]
fn run_command_safe(cmd: String, auth: Option<rocket::http::Header>) -> Result<String, Status> {
if let Some(header) = auth {
if header.name == "Authorization" {
if let Some(token) = header.value.strip_prefix("Bearer ") {
// Validate token format before use (example: alphanumeric + underscores)
if !token.chars().all(|c| c.is_alphanumeric() || c == '_' || c == '-') {
return Err(Status::BadRequest);
}
// Safe: no shell, arguments passed directly
let output = std::process::Command::new("echo")
.arg(token)
.arg(&cmd)
.output()
.map_err(|_| Status::InternalServerError)?;
return Ok(String::from_utf8_lossy(&output.stdout).to_string());
}
}
}
Err(Status::Unauthorized)
}
This approach eliminates shell injection by not invoking a shell. The token is treated as a literal argument, and a basic allowlist check ensures it does not contain unexpected characters. You can tighten validation further by using regex allowlists or by hashing the token before any external use, ensuring the original token never reaches the command layer.
For Rocket routes that must work with dynamic inputs, prefer structured data flows over string concatenation. If external tooling is required, consider using a controlled wrapper script with strict input sanitization and defined argument boundaries. Logging should redact token values—replace them with a hash or placeholder before writing to any output stream.
Applying these practices aligns with secure handling of Bearer Tokens in Rocket and reduces the attack surface for Command Injection. The key takeaway is to treat all external inputs—including authentication tokens—as untrusted and to avoid passing them through shell interpreters.
Related CWEs: inputValidation
| CWE ID | Name | Severity |
|---|---|---|
| CWE-20 | Improper Input Validation | HIGH |
| CWE-22 | Path Traversal | HIGH |
| CWE-74 | Injection | CRITICAL |
| CWE-77 | Command Injection | CRITICAL |
| CWE-78 | OS Command Injection | CRITICAL |
| CWE-79 | Cross-site Scripting (XSS) | HIGH |
| CWE-89 | SQL Injection | CRITICAL |
| CWE-90 | LDAP Injection | HIGH |
| CWE-91 | XML Injection | HIGH |
| CWE-94 | Code Injection | CRITICAL |