HIGH nosql injectionactixapi keys

Nosql Injection in Actix with Api Keys

Nosql Injection in Actix with Api Keys — how this specific combination creates or exposes the vulnerability

Nosql Injection occurs when user-controlled input is interpreted as part of a NoSQL query without proper validation or parameterization. In Actix web applications that use an embedded or external NoSQL store (for example, MongoDB via a Rust driver), this typically arises when query construction directly interpolates request data. If the application also relies on API keys for access control but does not validate or scope those keys against the data queries, the combination can expose both authorization bypass and injection paths.

Consider an Actix handler that retrieves a user profile using a user ID and an API key passed as headers or query parameters:

use actix_web::{get, web, HttpResponse, Responder};
use mongodb::{bson::{doc, Document}, options::ClientOptions, Client};

async fn get_profile(
    key: web::Header<actix_web::http::header::Authorization>,
    query: web::Query<std::collections::HashMap<String, String>>
) -> impl Responder {
    // Example: API key is used only for auth, not for query scoping
    let client = Client::with_uri_str("mongodb://localhost:27017").await.unwrap();
    let db = client.database("test");
    let coll = db.collection("profiles");

    // Vulnerable: user-controlled input directly used in document filter
    let user_id = query.get("user_id").unwrap_or(&"*".to_string());
    let filter = doc! { "_id": user_id };
    match coll.find_one(filter, None).await {
        Ok(Some(doc)) => HttpResponse::Ok().body(format!("{:?}", doc)),
        _ => HttpResponse::NotFound().finish(),
    }
}

If the API key is accepted but not used to constrain the query (for example, not used to ensure the caller can only access their own data), an authenticated attacker could manipulate user_id to perform NoSQL Injection. Injection payloads such as { "$ne": null } or { "$where": "return true" } can change query semantics, leading to unauthorized data access or data exfiltration. Because the API key in this scenario is used only for authentication and not bound to the query, the application fails to enforce proper ownership checks, amplifying the impact of a successful injection.

Furthermore, if the API key itself is reflected in logs or error messages, injection can assist in extracting those keys through output manipulation. The risk is not just data exposure but also privilege escalation when the injected query changes permissions or retrieves administrative data. This highlights why API keys in Actix must be tied to query scoping and input handling rather than treated as a one-time gate.

Api Keys-Specific Remediation in Actix — concrete code fixes

Remediation focuses on two goals: preventing NoSQL Injection by treating user input as data, not query fragments, and ensuring API keys are used to enforce data ownership. Below are concrete, safe patterns for Actix with MongoDB.

Never concatenate user input into a BSON document. Parse and validate inputs, then use bound values:

use actix_web::{get, web, HttpResponse, Responder, Result};
use mongodb::{bson::{doc, oid::ObjectId}, options::ClientOptions, Client};
use serde::Deserialize;

#[derive(Deserialize)]
struct ProfileQuery {
    user_id: String,
}

async fn get_profile_safe(
    key: web::Header<actix_web::http::header::Authorization>,
    query: web::Query<ProfileQuery>
) -> Result<impl Responder> {
    let client = Client::with_uri_str("mongodb://localhost:27017").await.unwrap();
    let db = client.database("test");
    let coll = db.collection("profiles");

    // Validate and normalize input
    let user_id = ObjectId::parse_str(&query.user_id)
        .map_err(|_| actix_web::error::ErrorBadRequest("Invalid user ID"))?;

    // Scoped query: bind both identity and ownership
    let filter = doc! { "_id": user_id };
    let opts = None;
    match coll.find_one(filter, opts).await {
        Ok(Some(doc)) => Ok(HttpResponse::Ok().body(format!("{:?}", doc))),
        _ => Ok(HttpResponse::NotFound().finish()),
    }
}

By parsing user_id into an ObjectId, we ensure the input matches the expected type and prevents injection via malformed queries.

Do not treat API keys as a simple on/off gate. Use them to scope data access, ensuring a caller cannot read other users’ documents:

use actix_web::HttpRequest;
use mongodb::bson::doc;

async fn get_profile_with_key(
    req: HttpRequest,
    query: web::Query<ProfileQuery>
) -> Result<impl Responder> {
    let client = Client::with_uri_str("mongodb://localhost:27017").await.unwrap();
    let db = client.database("test");
    let coll = db.collection("profiles");

    // Extract API key from headers (example scheme: ApiKey token)
    let api_key = req.headers()
        .get("X-API-Key")
        .and_then(|v| v.to_str().ok())
        .ok_or_else(|| actix_web::error::ErrorUnauthorized("Missing API key"))?;

    // In practice, validate api_key against a permissions store and derive user_id
    let allowed_user_id = lookup_user_for_key(api_key).map_err(|_| actix_web::error::ErrorForbidden("Insufficient scope"))?;

    // Enforce ownership in the filter
    let filter = doc! {
        "_id": ObjectId::parse_str(&query.user_id)?,
        "owner_key": api_key
    };
    let opts = None;
    match coll.find_one(filter, opts).await {
        Ok(Some(doc)) => Ok(HttpResponse::Ok().body(format!("{:?}", doc))),
        _ => Ok(HttpResponse::NotFound().finish()),
    }
}

fn lookup_user_for_key(_key: &str) -> Result<mongodb::bson::oid::ObjectId, &'static str> {
    // Stub: validate key and return associated user ObjectId
    Ok(ObjectId::new())
}

This pattern ensures the API key influences the query filter, preventing horizontal privilege escalation. Combined with input validation, it mitigates both injection and authorization flaws.

Do not echo API keys or raw user input in responses or logs. Use structured error handling:

use actix_web::error::JsonPayloadError;

async fn handle_errors(err: JsonPayloadError) -> HttpResponse {
    match err {
        JsonPayloadError::Deserialize(e) => {
            // Log safely without exposing keys or injection artifacts
            error!("Deserialization error: {}", e);
            HttpResponse::BadRequest().json("Invalid request")
        }
        _ => HttpResponse::BadRequest().json("Bad request"),
    }
}

Frequently Asked Questions

Can API keys alone prevent NoSQL Injection in Actix?
No. API keys provide authentication but do not prevent injection. You must validate and parameterize all user input and bind values in queries to avoid NoSQL Injection.
How does middleBrick assess API key related risks?
middleBrick scans unauthenticated attack surfaces and, where spec-defined, evaluates how API keys are used in authorization and query scoping. It reports findings such as BOLA/IDOR and insecure consumption patterns with remediation guidance.