Command Injection in Actix with Firestore
Command Injection in Actix with Firestore — how this specific combination creates or exposes the vulnerability
Command Injection occurs when an API accepts untrusted input and uses it to construct a system command passed to a shell or process executor. In an Actix web service that integrates with Google Cloud Firestore, this typically arises when server-side logic builds shell commands for administrative or data operations using values that originate from the request, such as document IDs, query parameters, or user-supplied metadata.
Consider an endpoint that dynamically constructs a gcloud or gsutil command using Firestore document identifiers. If the identifier is not strictly validated and is interpolated directly into the command string, an attacker can inject additional shell commands. For example, a document ID like doc1; cat /etc/passwd could cause the server to execute unintended operations. Because Firestore itself is a managed NoSQL database and does not execute shell commands, the risk emerges from the surrounding infrastructure — specifically, how the Actix service builds and invokes external processes that include Firestore-related data.
In the context of middleBrick’s 12 security checks, this scenario maps to the BFLA/Privilege Escalation and Input Validation categories. The scanner tests whether inputs that influence command construction can escape their intended context. It does not assume an internal architecture, but it does verify whether runtime behavior reflects unsafe handling of externally supplied data that references Firestore resources.
An unauthenticated attacker might probe endpoints that accept identifiers tied to Firestore documents and attempt to manipulate the command line. Successful injection could lead to information disclosure, unauthorized file access, or further lateral movement, depending on the permissions of the process executing the command. Because Firestore data often contains sensitive business logic, the exposure becomes particularly critical when combined with weak input validation in Actix route handlers.
Real-world examples include using Firestore document paths in backup scripts or log analysis tools where shell commands are assembled. If the Actix service runs with elevated privileges and does not sanitize or parameterize these values, the integration becomes a vector for compromise. middleBrick’s active testing includes command injection probes that simulate malicious input containing shell metacharacters to detect whether runtime behavior deviates from safe expectations.
Firestore-Specific Remediation in Actix — concrete code fixes
Remediation focuses on eliminating shell command construction entirely or strictly constraining inputs that reach the command layer. For Actix services interacting with Firestore, prefer the official Firestore client library for all data operations rather than invoking external tools. This removes the injection surface and aligns with secure coding practices for Google Cloud integrations.
If shell commands are unavoidable — for instance, to trigger Cloud Functions or batch operations — use strict allowlisting, avoid shell metacharacters, and leverage structured arguments instead of string concatenation. Below are examples demonstrating insecure patterns and their secure counterparts within an Actix handler.
Insecure pattern: direct string interpolation
use actix_web::{web, HttpResponse};
use std::process::Command;
async fn backup_document(doc_id: web::Path) -> HttpResponse {
let doc_id = doc_id.into_inner();
// UNSAFE: doc_id may contain shell metacharacters
let output = Command::new("sh")
.arg("-c")
.arg(format!("gcloud firestore documents export gs://backup-bucket/{} --collection-ids=users", doc_id))
.output();
match output {
Ok(o) if o.status.success() => HttpResponse::Ok().body("Backup started"),
_ => HttpResponse::InternalServerError().body("Backup failed"),
}
}
Secure pattern: use Firestore client and avoid shell
use actix_web::{web, HttpResponse};
use google_cloud_firestore::client::Client;
use google_cloud_firestore::document::Document;
async fn safe_backup_document(
doc_id: web::Path,
client: web::Data,
) -> HttpResponse {
let doc_id = doc_id.into_inner();
// Validate document ID format strictly
if !doc_id.chars().all(|c| c.is_alphanumeric() || c == '-' || c == '_') {
return HttpResponse::BadRequest().body("Invalid document ID");
}
let doc_ref = client.collection("users").doc(&doc_id);
let snapshot = match doc_ref.get().await {
Ok(s) => s,
Err(_) => return HttpResponse::NotFound().body("Document not found"),
};
// Process snapshot data without invoking a shell
// Example: serialize or copy to another Firestore location
HttpResponse::Ok().json(snapshot)
}
Secure pattern: if external commands are required
When external tooling is necessary, pass arguments as a list and avoid a shell wrapper:
use std::process::Command;
fn export_with_args(doc_id: &str) -> std::process::Output {
// Allowlist regex: alphanumeric, dash, underscore
if !doc_id.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_') {
panic!("Invalid document ID");
}
Command::new("gcloud")
.arg("firestore")
.arg("documents")
.arg("export")
.arg("gs://backup-bucket")
.arg(format!("--document-id={}", doc_id))
.output()
}
In all cases, validate Firestore identifiers against a strict character allowlist, normalize inputs, and log suspicious attempts. middleBrick’s dashboard and CLI can be used to verify that your endpoints no longer reflect user-controlled data in command lines, and the GitHub Action can enforce that no new insecure patterns are introduced in pull requests.
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 |