Nosql Injection in Actix
How Nosql Injection Manifests in Actix
Nosql injection in Actix applications typically occurs when user input is directly incorporated into MongoDB queries without proper sanitization. Actix developers often use the MongoDB Rust driver or libraries like mongodb to interact with NoSQL databases. The vulnerability arises when query parameters are constructed using unsanitized request data.
Here's a common vulnerable pattern in Actix:
use actix_web::{web, HttpResponse};
use mongodb::{bson::doc, options::FindOptions};
async fn search_users(info: web::Json<SearchQuery>) -> Result<HttpResponse> {
let client = Client::with_uri_str("mongodb://localhost:27017").await?;
let collection = client.database("mydb").collection("users");
// Vulnerable: Direct interpolation of user input
let filter = doc! {
"username": info.username.clone(),
"age": { "$gt": info.min_age }
};
let results = collection.find(filter, None).await?;
Ok(HttpResponse::Ok().json(results))
}
The vulnerability becomes critical when attackers can inject MongoDB operators. For example, if info.username contains { "$ne": null }, the query changes behavior entirely. More dangerous is when users supply { "$where": "this.age == this.password.length" } or similar JavaScript injection attempts.
Actix's async/await patterns can make these vulnerabilities harder to spot. Developers might chain multiple operations where user input flows through several transformation steps before reaching the database layer:
async fn get_sensitive_data(
web::Query(params): web::Query<HashMap<String, String>>,
) -> Result<HttpResponse> {
let client = Client::with_uri_str("mongodb://localhost:27017").await?;
let collection = client.database("mydb").collection("secrets");
// Even worse: user controls entire query document
let filter = bson::from_bson(bson::Bson::String(params.get("query").unwrap_or_default().clone()))?;
let results = collection.find(filter, None).await?;
Ok(HttpResponse::Ok().json(results))
}
The Actix web framework's strong typing can actually create a false sense of security. Developers might assume that because their route handlers are type-safe, their database queries are safe too. This isn't the case when using dynamic query builders or when deserializing JSON directly into BSON documents.
Actix-Specific Detection
Detecting NoSQL injection in Actix applications requires examining both the code structure and runtime behavior. middleBrick's black-box scanning approach is particularly effective for Actix APIs because it tests the actual HTTP endpoints without needing source code access.
When middleBrick scans an Actix API, it specifically looks for NoSQL injection patterns by:
- Testing for MongoDB operator injection by submitting payloads containing
$ne,$gt,$where, and other operators - Checking for JavaScript injection in
$whereclauses by submitting simple comparison functions - Testing for type confusion attacks by submitting different data types (numbers as strings, objects as arrays)
- Analyzing response differences to detect information leakage through error messages
For Actix developers, the CLI tool provides immediate feedback:
$ npm install -g middlebrick
$ middlebrick scan https://api.example.com/users
The scan tests endpoints with payloads like:
{
"username": { "$ne": null },
"password": { "$exists": true }
}
If the API returns different results or error messages, middleBrick flags this as a potential NoSQL injection vulnerability. The tool also checks for proper content-type headers and validates that JSON responses are correctly formatted, as NoSQL injection often causes serialization errors.
For CI/CD integration, the GitHub Action can be configured to fail builds when NoSQL injection risks are detected:
name: Security Scan
on: [push, pull_request]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run middleBrick Scan
uses: middlebrick/middlebrick-action@v1
with:
target_url: ${{ secrets.API_URL }}
fail_below: B
token: ${{ secrets.MIDDLEBRICK_TOKEN }}
This ensures that NoSQL injection vulnerabilities are caught before deployment to production environments.
Actix-Specific Remediation
Remediating NoSQL injection in Actix requires a defense-in-depth approach. The most effective strategy combines input validation, parameterized queries, and strict type enforcement.
First, validate all input using Actix's type system and custom validators:
use actix_web::{web, HttpResponse, HttpMessage};
use serde::{Deserialize, Serialize};
use mongodb::{bson::doc, options::FindOptions};
#[derive(Deserialize, Serialize)]
struct SearchQuery {
#[serde(deserialize_with = "validate_username")]
username: String,
#[serde(deserialize_with = "validate_age")]
min_age: i32,
}
fn validate_username<'de, D>(deserializer: D) -> Result<String, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
if s.contains('$') || s.contains('{') || s.contains('}') {
return Err(serde::de::Error::custom("Invalid characters in username"));
}
Ok(s)
}
fn validate_age<'de, D>(deserializer: D) -> Result<i32, D::Error>
where
D: serde::Deserializer<'de>,
{
let age = i32::deserialize(deserializer)?;
if age < 0 || age > 150 {
return Err(serde::de::Error::custom("Age out of valid range"));
}
Ok(age)
}
async fn search_users(
info: web::Json<SearchQuery>,
) -> Result<HttpResponse> {
let client = Client::with_uri_str("mongodb://localhost:27017").await?;
let collection = client.database("mydb").collection("users");
// Safe: input is validated before query construction
let filter = doc! {
"username": info.username.clone(),
"age": { "$gt": info.min_age }
};
let results = collection.find(filter, None).await?;
Ok(HttpResponse::Ok().json(results))
}
For more complex queries, use MongoDB's aggregation framework with explicit pipeline stages rather than dynamic query documents:
async fn get_users_by_criteria(
web::Query(params): web::Query<HashMap<String, String>>,
) -> Result<HttpResponse> {
let client = Client::with_uri_str("mongodb://localhost:27017").await?;
let collection = client.database("mydb").collection("users");
// Build pipeline with explicit stages
let mut pipeline = vec![];
if let Some(username) = params.get("username") {
pipeline.push(doc! { "$match": { "username": username } });
}
if let Some(age_str) = params.get("min_age") {
if let Ok(age) = age_str.parse::() {
pipeline.push(doc! { "$match": { "age": { "$gt": age } } });
}
}
let results = collection.aggregate(pipeline, None).await?;
Ok(HttpResponse::Ok().json(results))
}
The aggregation pipeline approach ensures that each stage is explicitly defined and cannot be manipulated through operator injection. Additionally, consider using MongoDB's built-in query sanitizers or libraries like mongodb-sanitize that automatically escape dangerous characters.
For Actix applications with extensive NoSQL interactions, implement a query builder layer that enforces schema validation before any database operation. This layer should reject any query containing MongoDB operators unless explicitly allowed through a whitelist approach.
Frequently Asked Questions
How does NoSQL injection differ from SQL injection in Actix applications?
NoSQL injection in Actix applications targets document databases like MongoDB rather than relational databases. While SQL injection exploits query syntax and string concatenation, NoSQL injection leverages the flexible document structure and query operators. MongoDB allows JavaScript execution in $where clauses and supports operators like $ne, $gt, and $exists that can be manipulated through request parameters. Actix developers must sanitize input to prevent these operators from being injected, whereas SQL injection typically requires escaping quotes and preventing UNION-based attacks.
Can middleBrick detect NoSQL injection in Actix applications without source code access?
Yes, middleBrick performs black-box scanning that tests Actix API endpoints without requiring source code or credentials. The scanner sends payloads containing MongoDB operators like $ne, $where, and $exists to identify injection points. It analyzes response differences, error messages, and data exposure patterns to detect vulnerabilities. The 5-15 second scan tests the unauthenticated attack surface, making it ideal for Actix applications where the API might be publicly accessible. middleBrick's findings include severity levels and specific remediation guidance for each detected vulnerability.