Nosql Injection in Actix with Dynamodb
Nosql Injection in Actix with Dynamodb — how this specific combination creates or exposes the vulnerability
NoSQL injection in Actix services that interact with Amazon DynamoDB typically arises when user-controlled input is directly interpolated into DynamoDB expression attribute values or key condition expressions without proper validation or parameterization. In an Actix web application written in Rust, this can occur when building DynamoDB requests dynamically, for example by concatenating user input into the KeyConditionExpression or FilterExpression strings instead of using expression attribute values.
Consider an endpoint that retrieves a user profile by user_id provided via a query parameter. If the route handler builds the request like this:
let user_id = web::Query::from_query(&req.query_string()).unwrap().0.get("user_id").unwrap_or(&"").to_string();
let key_cond = format!("user_id = {user_id}");
let req = GetItemInput {
table_name: Some("Users".to_string()),
key: hashmap!{"user_id".to_string() => AttributeValue::S(user_id)},
// ...
};
Although this example uses a hash key directly, unsafe construction of expressions elsewhere (such as Scan with a filter) can allow an attacker to inject expression syntax. A malicious input like 1 OR #a = #a in a vulnerable string-based filter could change the logical evaluation, potentially bypassing intended access controls or exposing other users’ data when combined with an over-permissive Scan or Query that lacks strict key conditions.
DynamoDB’s JSON-like structure and expression syntax enable injection if inputs are placed into expression names or values incorrectly. In Actix, if the application uses the low-level DynamoDB client and builds expression strings by interpolating user data, it may unintentionally expose the attack surface. For instance, using user input as an expression attribute name without validation can lead to path traversal across attributes, or injecting logical operators into a FilterExpression can alter the intended filtering logic.
The risk is compounded when the Actix service performs unauthenticated scans or exposes administrative endpoints that rely on dynamic expressions. An attacker may leverage NoSQL injection to enumerate data, bypass row-level ownership checks (BOLA/IDOR), or extract sensitive items by manipulating the conditional logic. Because DynamoDB does not support parameterized queries in the same way relational databases do, developers must explicitly use expression attribute values and expression attribute names to prevent injection.
middleBrick’s scans detect such issues by submitting inputs that probe expression parsing and access controls, flagging missing parameterization and overly permissive filter logic. The scanner’s checks include input validation and BOLA/IDOR assessments, which can surface NoSQL injection vectors in DynamoDB-backed Actix APIs.
Dynamodb-Specific Remediation in Actix — concrete code fixes
To remediate NoSQL injection in Actix with DynamoDB, always use expression attribute values and expression attribute names for any user-controlled data. Never concatenate user input into key condition expressions, filter expressions, or attribute path segments. The following examples show safe patterns using the official AWS SDK for Rust.
Safe Query with Key Condition Expression
When querying by partition key, supply the key value directly in the key field and use a placeholder in the expression. Do not embed the value in the expression string.
use aws_sdk_dynamodb::types::AttributeValue;
use aws_sdk_dynamodb::Client;
async fn get_user_profile(client: &Client, user_id: &str) -> Result<_, aws_sdk_dynamodb::Error> {
let req = client.get_item()
.table_name("Users")
.key("user_id", AttributeValue::S(user_id.to_string()))
.expression_attribute_values(
":uid",
AttributeValue::S(user_id.to_string()),
)
.key_condition_expression("user_id = :uid")
.send()
.await?
.into_body();
// handle response
todo!()
}
Safe Scan with Filter Expression
For scans, use expression attribute names for dynamic field names and expression attribute values for data values. Validate and map user input to known attribute names on the server side before referencing them.
async fn scan_users_by_status(client: &Client, status_value: &str) -> Result<_, aws_sdk_dynamodb::Error> {
let req = client.scan()
.table_name("Users")
.filter_expression("#st = :val")
.expression_attribute_names({
let mut map = std::collections::HashMap::new();
map.insert("#st".to_string(), "status".to_string());
map
})
.expression_attribute_values(
":val",
AttributeValue::S(status_value.to_string()),
)
.send()
.await?
.into_body();
// handle response
todo!()
}
Defensive Practices in Actix Handlers
- Validate and whitelist input values wherever possible (e.g., allow only known status strings).
- Use strongly typed request structures with Actix’s extractor validation to reject malformed input early.
- Apply principle of least privilege to the IAM role associated with the DynamoDB client to limit the impact of any potential injection.
By consistently using expression attribute placeholders and avoiding string interpolation for expressions, the Actix service eliminates the injection vector while preserving the flexibility of DynamoDB queries and scans.
Frequently Asked Questions
How can I test if my Actix API with DynamoDB is vulnerable to NoSQL injection?
1 OR #a = #a) in query parameters or filter fields and observing whether the behavior changes unexpectedly.