GuardAPI Logo
GuardAPI
GuardAPI Logo GuardAPI

Fix Command Injection in Actix Web

Command injection in Actix Web occurs when user-controlled data is passed directly to system shells or process builders without proper sanitization or parameterization. In Rust, utilizing `std::process::Command` with `sh -c` or similar shell wrappers is the primary vector for this vulnerability, allowing attackers to break out of the intended command context using shell metacharacters like `;`, `&`, `|`, or backticks.

The Vulnerable Pattern

use actix_web::{web, HttpResponse, Responder};
use std::process::Command;
use serde::Deserialize;

#[derive(Deserialize)] pub struct Params { target: String, }

async fn check_health(info: web::Query) -> impl Responder { // DANGER: User input is concatenated into a shell command string let output = Command::new(“sh”) .arg(“-c”) .arg(format!(“curl -I {}”, info.target)) .output();

match output {
    Ok(out) => HttpResponse::Ok().body(String::from_utf8_lossy(&out.stdout).to_string()),
    Err(_) => HttpResponse::InternalServerError().finish(),
}

}

The Secure Implementation

The fix implements a defense-in-depth strategy. First, it removes the shell invocation (`sh -c`). By calling the binary (`curl`) directly and passing arguments via `.arg()`, the OS treats the input as a literal string for the process rather than interpreting it for shell tokens. Second, it adds strict regex validation to ensure the input matches an expected pattern (e.g., a hostname), preventing any unexpected characters from reaching the process execution layer.

use actix_web::{web, HttpResponse, Responder};
use std::process::Command;
use serde::Deserialize;
use regex::Regex;

#[derive(Deserialize)] pub struct Params { target: String, }

async fn check_health_secure(info: web::Query) -> impl Responder { // 1. Strict Input Validation (Allowlist/Regex) let re = Regex::new(r”^[a-zA-Z0-9.-]+$“).unwrap(); if !re.is_match(&info.target) { return HttpResponse::BadRequest().body(“Invalid target format”); }

// 2. Parameterization: Pass arguments directly to the binary, bypassing the shell
let output = Command::new("curl")
    .arg("-I")
    .arg(&info.target) // This is treated as a literal argument, not a shell command
    .output();

match output {
    Ok(out) => HttpResponse::Ok().body(String::from_utf8_lossy(&out.stdout).to_string()),
    Err(_) => HttpResponse::InternalServerError().finish(),
}

}

System Alert • ID: 4693
Target: Actix Web API
Potential Vulnerability

Your Actix Web API might be exposed to Command Injection

74% of Actix Web apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.

RUN FREE SECURITY DIAGNOSTIC
GuardLabs Engine: ONLINE

Free Tier • No Credit Card • Instant Report

Verified by Ghost Labs Security Team

This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.