GuardAPI Logo
GuardAPI
Automated Security Protocol

How to fix NoSQL Injection
in Salvo

Executive Summary

NoSQL Injection in Salvo handlers typically occurs when raw user input is deserialized into a generic map or JSON object and passed directly into a database query filter. In Rust, while the type system provides some protection, using dynamic keys or nested objects in BSON documents allows attackers to inject operators like $gt, $ne, or $regex to bypass authentication or exfiltrate data. To secure Salvo apps, you must enforce strict schema validation using Serde and avoid passing raw JSON values into MongoDB's doc! macro.

The Vulnerable Pattern

VULNERABLE CODE
use salvo::prelude::*;
use mongodb::bson::doc;

#[handler] async fn vulnerable_login(req: &mut Request, res: &mut Response) { // DANGER: Parsing into a generic Value allows nested objects let body: serde_json::Value = req.parse_json().await.unwrap();

// If body is {"user": {"$ne": ""}, "pass": {"$ne": ""}}, the query returns the first user
let filter = doc! {
    "username": body["username"].clone(),
    "password": body["password"].clone()
};

let user = db.collection::<User>("users").find_one(filter, None).await;
res.render(Json(user));

}

The Secure Implementation

The vulnerability lies in the use of `serde_json::Value`. When the MongoDB driver's `doc!` macro receives a `Value`, it can interpret nested objects as query operators. An attacker can send a JSON payload where the 'username' field is an object `{"$ne": null}`, causing the database to return any user. The fix involves defining a strict Rust `struct` for the request body. By typing the fields as `String`, Serde will fail to deserialize the request if the attacker provides an object instead of a literal string, effectively neutralizing the injection vector before it reaches the database driver.

SECURE CODE
use salvo::prelude::*;
use mongodb::bson::doc;
use serde::Deserialize;

#[derive(Deserialize)] struct LoginRequest { username: String, password: String, }

#[handler] async fn secure_login(req: &mut Request, res: &mut Response) { // FIX: Parse into a strictly typed struct. // This forces input to be Strings, preventing operator injection. let login: LoginRequest = match req.parse_json().await { Ok(data) => data, Err(_) => return res.status_code(StatusCode::BAD_REQUEST), };

let filter = doc! {
    "username": &login.username,
    "password": &login.password
};

let user = db.collection::<User>("users").find_one(filter, None).await;
res.render(Json(user));

}

System Alert • ID: 5771
Target: Salvo API
Potential Vulnerability

Your Salvo API might be exposed to NoSQL Injection

74% of Salvo apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.

RUN FREE SECURITY DIAGNOSTIC
GuardLabs Engine: ONLINE

Free Tier • No Credit Card • Instant Report

Verified by Ghost Labs Security Team

This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.