Nosql Injection in Actix with Cockroachdb
Nosql Injection in Actix with Cockroachdb — how this specific combination creates or exposes the vulnerability
NoSQL injection in an Actix-web service that uses CockroachDB typically arises when application code builds database queries by concatenating user-controlled input into JSON or BSON structures, or when dynamic filter objects are constructed without validation. Unlike SQL, NoSQL databases often rely on query languages that interpret operators and nested documents, and careless construction of filters can allow an attacker to affect query logic beyond simple record retrieval.
Consider an endpoint that accepts JSON query hints to filter tenant data. If the handler directly deserializes incoming JSON into a serde_json::Value and embeds it into a match expression used to build a CockroachDB SQL string or ORM query, special keys such as $ne, $exists, or $regex may be interpreted as operators rather than literal field names. This can cause the query to return unintended rows, bypass intended access controls, or expose sensitive documents.
In a microservice architecture, Actix routes often pass extracted parameters (e.g., user identifiers) into downstream query builders. When those parameters are merged into a NoSQL-style filter without normalization or allowlisting, the attack surface expands. An attacker may supply payloads like {"tenantId": "1", "$or": [{"password": {"$exists": true}}]} to probe for existence of privileged fields. Because CockroachDB supports JSONB and expressive indexing, such payloads can influence execution paths or data visibility when the query is translated into SQL by an ORM or driver.
The risk is compounded when the API exposes document structures that reference internal schema details. If responses include metadata or nested arrays, an attacker can use injection to extract or infer additional data relationships. Although the scan reports this as a general Data Exposure and Input Validation finding, the specific vector in this stack is the uncontrolled propagation of user input into NoSQL-style query constructs that ultimately reach CockroachDB.
middleBrick detects these patterns by correlating OpenAPI/Swagger definitions with runtime behavior, flagging endpoints where untrusted data flows into database query construction. The tool does not fix the logic, but provides prioritized findings with remediation guidance to help developers redesign how filters are built and validated.
Cockroachdb-Specific Remediation in Actix — concrete code fixes
Secure handling of user input in Actix with CockroachDB centers on strict schema validation, parameterized queries, and avoiding dynamic injection of operators into query structures. Below are concrete patterns that reduce NoSQL injection risk.
1. Use strongly typed structures instead of raw JSON
Define a Rust struct that describes exactly which fields are permitted, and deserialize incoming data into that structure. This prevents unexpected keys such as $ne or $exists from being interpreted as operators.
use actix_web::{web, HttpResponse};
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
struct TenantQuery {
tenant_id: i64,
active_only: bool,
}
async fn list_tenants(query: web::Query) -> HttpResponse {
let sql = "SELECT id, name FROM tenants WHERE tenant_id = $1 AND active = $2";
// Use a CockroachDB driver/ORM to execute the parameterized query
// Example placeholder: let rows = crdb_client.query(sql, &[&query.tenant_id, &query.active_only]).await;
HttpResponse::Ok().body(format!("Executing: {} with params: {}, {}", sql, query.tenant_id, query.active_only))
}
2. Avoid embedding user input directly into query strings or dynamic filters
If you must build dynamic filters, use an allowlist of known fields and explicit mapping instead of passing raw user input into the query builder.
use serde_json::Value;
fn build_safe_filter(base: &str, filters: &Value) -> String {
// Only allow known fields; ignore or reject unexpected keys
if let Some(obj) = filters.as_object() {
let conditions: Vec = obj.iter()
.filter(|(k, _)| ["name", "status"].contains(&k.as_str()))
.map(|(k, v)| format!("{key} = {value}", key = k, value = v.as_str().unwrap_or("")))
.collect();
format!("{} WHERE {}", base, conditions.join(" AND "))
} else {
base.to_string()
}
}
// Usage: let safe_sql = build_safe_filter("SELECT * FROM tenants", &input_json);
3. Leverage CockroachDB’s parameterized capabilities and avoid string interpolation
Always prefer placeholders over injecting values directly. Even when using JSONB columns, validate the content of the JSON rather than trusting the keys provided by the client.
// Example with a CockroachDB Rust driver placeholder pattern
async fn find_by_jsonb_field(client: &cockroachdb::Client, filter_json: &str) -> Result<(), Box> {
// Validate filter_json schema before use; do not directly embed into SQL
let sql = "SELECT data FROM tenant_metadata WHERE meta ?& ARRAY['status'] AND data @> $1";
// client.execute(sql, &[&filter_json]).await;
Ok(())
}
4. Normalize keys and reject operators
Strip or reject known operator prefixes such as $ patterns (e.g., $ne, $regex, $or) before using any input to construct a query. This ensures that attacker-supplied keys cannot alter the semantics of the generated SQL or JSONB queries.
fn sanitize_input(value: &str) -> bool {
!value.starts_with('$')
}
By combining strong typing, strict allowlists, and parameterized execution, you can mitigate NoSQL injection risks in an Actix service backed by CockroachDB. middleBrick can help identify endpoints where user input flows into query construction, enabling you to apply these patterns systematically.