Xpath Injection in Actix with Firestore
Xpath Injection in Actix with Firestore — how this specific combination creates or exposes the vulnerability
XPath Injection occurs when untrusted data is concatenated into an XPath expression without proper escaping or parameterization, allowing an attacker to alter the query logic. In an Actix web service that uses Firestore as a backend, risk arises when the application builds XPath filters from HTTP request inputs (e.g., query parameters or JSON fields) and passes them to Firestore operations that are interpreted as XPath-like selectors or used to construct downstream queries.
Consider an endpoint in Actix that retrieves a user document by username: the handler reads a username query parameter and uses it to build a filter string that is later evaluated by an internal layer that maps logical conditions to Firestore-compatible semantics. If the application does not sanitize or parameterize the input, an attacker can supply a value such as ' or '1'='1, which changes the logical structure of the composed query. Because Firestore rules and SDK behavior can be influenced by how selectors are constructed, an attacker may bypass intended access controls or enumerate data that should remain restricted.
The exposure is compounded when the Actix service uses OpenAPI/Swagger specs with $ref resolution to document query schemas without validating runtime construction of selectors. A scan using middleBrick can detect these injection-prone patterns by correlating the spec-defined parameters with runtime behavior, highlighting where untrusted input reaches selector-building code. This is distinct from general input validation; the issue is specific to how expressions are composed and interpreted, not merely whether input conforms to a format.
Real-world impact can include unauthorized data access or enumeration, which maps to the OWASP API Top 10:2023 Broken Object Level Authorization (BOLA/IDOR) and Input Validation categories. For compliance, findings may align with PCI-DSS and SOC2 controls related to access restrictions and auditability. middleBrick’s runtime checks correlate spec definitions with observed behavior to surface these risks, providing severity, context, and remediation guidance rather than attempting to block or fix the endpoint.
Firestore-Specific Remediation in Actix — concrete code fixes
To prevent XPath Injection in Actix when working with Firestore, avoid building selectors by string concatenation. Instead, use structured, parameterized approaches and rely on Firestore SDK features for safe data access. Below are concrete patterns and code examples for Actix handlers.
1. Use Firestore SDK queries with explicit field filters
Do not construct filter strings from user input. Use the Firestore SDK’s query methods with explicit field-value pairs. In Rust with the Firestore SDK, prefer typed structs and the filter API.
use actix_web::{web, HttpResponse};
use firestore::FirestoreDb;
use serde::Deserialize;
#[derive(Deserialize)]
struct UserQuery {
username: String,
}
async fn get_user_by_username(
db: web::Data,
query: web::Query,
) -> HttpResponse {
// Safe: field name is hardcoded, value is parameterized by the SDK
let docs = db
.collection("users")
.add_filter("username", "==", &query.username)
.get()
.await;
match docs {
Ok(users) if !users.is_empty() => HttpResponse::Ok().json(users),
Ok(_) => HttpResponse::NotFound().body("User not found"),
Err(e) => {
// Log the error appropriately in your application
HttpResponse::InternalServerError().body(format!("Error: {:?}", e))
}
}
}
2. Validate and normalize input before use
If your data model requires dynamic selectors, validate input strictly and normalize it before use. For example, allow only alphanumeric usernames and reject characters used in XPath syntax.
fn safe_username(input: &str) -> bool {
// Allow only letters, digits, underscore, and hyphen
input.chars().all(|c| c.is_alphanumeric() || c == '_' || c == '-')
}
async fn safe_handler(
db: web::Data,
web::Query(params): web::Query>,
) -> HttpResponse {
if let Some(username) = params.get("username") {
if !safe_username(username) {
return HttpResponse::BadRequest().body("Invalid username");
}
let docs = db.collection("users")
.add_filter("username", "==", username)
.get()
.await;
// handle response as above
} else {
HttpResponse::BadRequest().body("Missing username")
}
}
3. Prefer Firestore security rules for access control
Do not encode access decisions in XPath-like selector strings. Use Firestore security rules to enforce read/write permissions based on request authentication and resource ownership. This ensures that even if an injection attempt reaches the backend, the rules layer will deny unauthorized access.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, write: if request.auth != null && request.auth.uid == userId;
}
}
}