Path Traversal in Actix with Firestore
Path Traversal in Actix with Firestore — how this specific combination creates or exposes the vulnerability
Path Traversal occurs when an API allows user-supplied input to directly influence filesystem or database paths without sufficient validation or sanitization. In an Actix web service that uses Google Cloud Firestore as a backend, this typically manifests through document or collection identifiers derived from unchecked request parameters. Because Firestore organizes data hierarchically (projects → collections → documents), a path-like input such as a document ID or subcollection name can be concatenated into a read or write operation without normalization, enabling sequences like ../../../secrets/config to escape the intended scope.
When Firestore rules are permissive or when the server-side code assumes client-supplied paths are safe, an attacker can leverage path traversal to access or affect documents outside the authorized namespace. For example, if an endpoint accepts a document_path query parameter and passes it to doc_ref without canonicalization, an input such as users/attacker/../admin/privileges may resolve to an administrative document if the server does not enforce ownership checks. This becomes more impactful when combined with Firestore’s support for subcollections, where a path like organizations/abc/users/../../admin/roles could traverse up a logical hierarchy if the server-side resolver does not validate boundaries.
Moreover, because middleBrick tests unauthenticated attack surfaces, a misconfigured endpoint that exposes Firestore metadata or error messages can reveal whether traversal attempts are being interpreted as valid document paths. While Firestore itself does not provide a traditional filesystem, the logical path structure can be abused to reference unintended documents or collections when server-side code does not enforce strict allow-lists on identifiers. The combination of Actix’s routing flexibility and Firestore’s hierarchical model increases the importance of rigorous input validation and strict scoping to ensure every read or write targets exactly the intended resource.
Firestore-Specific Remediation in Actix — concrete code fixes
To mitigate path traversal in an Actix application using Firestore, you must validate and constrain all user-controlled inputs that contribute to document references. The safest approach is to avoid building Firestore paths from raw user input. Instead, use allow-lists, strict regex patterns, or precomputed document keys. When you must accept a path-like identifier, canonicalize and validate it before using it in Firestore operations.
Below are concrete, Firestore-specific code examples for Actix that demonstrate secure handling of document identifiers.
1. Strict allow-list validation for document IDs
Accept only alphanumeric IDs (with limited safe characters) and reject any string containing path-like sequences.
use actix_web::{web, HttpResponse};
use google_cloud_firestore::client::Client;
use regex::Regex;
async fn get_user_document(
client: web::Data,
path: web::Path,
) -> HttpResponse {
let candidate = path.into_inner();
// Allow only alphanumeric IDs; reject slashes, dots, and special characters
let re = Regex::new(r"^[a-zA-Z0-9_-]{1,100}$").unwrap();
if !re.is_match(&candidate) {
return HttpResponse::BadRequest().body("Invalid document identifier");
}
let doc_ref = client.doc(&format!("users/{}", candidate));
match doc_ref.get().await {
Ok(snapshot) => {
if snapshot.exists() {
HttpResponse::Ok().json(snapshot.data::().unwrap_or_default())
} else {
HttpResponse::NotFound().body("Document not found")
}
}
Err(e) => HttpResponse::InternalServerError().body(format!("Firestore error: {}", e)),
}
}
2. Avoid path concatenation; use document IDs only
Do not accept full paths. Instead, accept a single document ID and construct the reference server-side with a fixed collection prefix.
async fn get_secure_document(
client: web::Data,
doc_id: web::Path,
) -> HttpResponse {
let id = doc_id.into_inner();
// Enforce business-rule constraints (e.g., length, format)
if id.len() > 200 || id.contains('/') || id.contains('\\') {
return HttpResponse::BadRequest().body("Invalid document ID");
}
// Fixed collection ensures traversal is not possible
let document_path = format!("app_data/records/{}", id);
let doc_ref = client.doc(&document_path);
// Proceed with secure read
match doc_ref.get().await {
Ok(snapshot) => { /* handle response */ }
Err(_) => HttpResponse::InternalServerError().body("Database error"),
}
}
3. Use Firestore transactions with explicit lookups
When reading related documents, avoid dynamic path assembly. Use explicit collection and document references.
async fn read_related_data(
client: web::Data,
org_id: web::Path,
user_id: web::Path,
) -> HttpResponse {
let org = org_id.into_inner();
let user = user_id.into_inner();
// Validate both identifiers independently
if !is_valid_id(&org) || !is_valid_id(&user) {
return HttpResponse::BadRequest().body("Invalid identifier");
}
let org_ref = client.doc(&format!("organizations/{}", org));
let user_ref = client.doc(&format!("organizations/{}/members/{}", org, user));
// Transaction to ensure consistency
let result = client.run_transaction(|transaction| {
Box::pin(async move {
let org_data = transaction.get(&org_ref).await?;
let user_data = transaction.get(&user_ref).await?;
// Combine securely
Ok((org_data, user_data))
})
}).await;
match result {
Ok((o, u)) => HttpResponse::Ok().json((o, u)),
Err(_) => HttpResponse::NotFound().finish(),
}
}
fn is_valid_id(id: &str) -> bool {
id.chars().all(|c| c.is_alphanumeric() || c == '-' || c == '_') && id.len() <= 128
}
These patterns ensure that user input never directly dictates traversal across Firestore logical paths. By combining strict validation, fixed collection structures, and server-side path construction, you reduce the risk of path traversal while preserving the flexibility of Firestore’s document model.
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 |