HIGH pii leakageaxumdynamodb

Pii Leakage in Axum with Dynamodb

Pii Leakage in Axum with Dynamodb — how this specific combination creates or exposes the vulnerability

When building a Rust web service with the Axum framework that uses Amazon DynamoDB as a persistence layer, PII leakage commonly occurs at the intersection of application logic, data modeling, and DynamoDB access patterns. Axum provides a flexible handler model where request data is deserialized into Rust structs, and developers often map those structs directly to DynamoDB item representations. If the structs include fields such as email, phone, national ID, or other personal data and the DynamoDB table stores those fields in clear text, any over-broad read or scan operation can expose PII. A typical pattern is an endpoint that calls get_item or query and then serializes the returned item into a response; if the response includes the full item or a subset that still contains sensitive attributes, PII is exposed to clients or logs.

DynamoDB-specific risks amplify this when developers use sparse indexes or query filters that inadvertently return items with PII. For example, a Global Secondary Index (GSI) on a non-sensitive attribute like status can return full items (including PII) unless a projection is explicitly limited to key attributes only. Additionally, conditional writes and update expressions that set attributes based on request input can write PII into the item if input validation is missing in Axum handlers. Without runtime validation and strict field selection, an attacker who can manipulate query parameters or path variables may cause the application to retrieve or list items containing personally identifiable information, effectively turning DynamoDB into an unintentional PII export channel.

Another vector specific to the Axum + DynamoDB stack is logging and tracing. If Axum middleware or custom code logs the full request or response for debugging and the response includes data fetched from DynamoDB, PII can be persisted in logs or monitoring systems. Insecure deserialization of DynamoDB streams or Data Streams consumers can also replay PII into downstream systems if consumers are not designed to filter or redact sensitive attributes. These concerns align with the OWASP API Top 10 (2023) A01:2023 Broken Object Level Authorization and A05:2023 Security Misconfiguration, where excessive data exposure and improper error handling expose sensitive information.

Dynamodb-Specific Remediation in Axum — concrete code fixes

Remediation focuses on minimizing data exposure in DynamoDB operations and enforcing strict data handling in Axum handlers. Use explicit projection expressions in GetItem, Query, and Scan to return only non-PII attributes unless PII is explicitly required. When PII must be stored, enable DynamoDB encryption at rest and use fine-grained IAM policies to restrict which roles and principals can access sensitive attributes. In Axum, structure responses with dedicated serializers that omit sensitive fields and validate inputs before constructing query expressions.

Below are concrete Rust examples for Axum with the official AWS SDK for Rust (aws-sdk-dynamodb). The first example shows a safe query that projects only public attributes, avoiding PII leakage.

use aws_sdk_dynamodb::types::AttributeValue;
use aws_sdk_dynamodb::Client;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct PublicProfile {
    pub user_id: String,
    pub display_name: String,
}

async fn get_public_profile(
    client: &Client,
    table_name: &str,
    user_id: &str,
) -> Result> {
    let response = client
        .get_item()
        .table_name(table_name)
        .key("user_id", AttributeValue::S(user_id.to_string()))
        .projection_expression("user_id, display_name") // only non-PII fields
        .send()
        .await?;

    let item = response.item.ok_or("Item not found")?;
    let profile = PublicProfile {
        user_id: item.get("user_id")
            .and_then(|v| v.as_s().ok())
            .unwrap_or(&"".to_string())
            .clone(),
        display_name: item.get("display_name")
            .and_then(|v| v.as_s().ok())
            .unwrap_or(&"".to_string())
            .clone(),
    };
    Ok(profile)
}

The second example demonstrates a query with a GSI that limits projections and uses a filter expression to avoid returning PII. It avoids scanning all attributes and ensures only intended fields are retrieved.

async fn query_public_index(
    client: &Client,
    table_name: &str,
    index_name: &str,
    status: &str,
) -> Result, Box> {
    let response = client
        .query()
        .table_name(table_name)
        .index_name(index_name)
        .key_condition_expression("status = :status")
        .expression_attribute_values(":status", AttributeValue::S(status.to_string()))
        .projection_expression("user_id, display_name") // limit to safe attributes
        .send()
        .await?;

    let profiles: Vec = response.items.into_iter().filter_map(|item| {
        Some(PublicProfile {
            user_id: item.get("user_id")?.as_s().ok()?.clone(),
            display_name: item.get("display_name")?.as_s().ok()?.clone(),
        })
    }).collect();
    Ok(profiles)
}

In Axum handlers, always validate and sanitize inputs before using them in DynamoDB expressions. Avoid passing raw user input into a Scan or Query filter that could return PII. Use select statements in responses (e.g., using serde’s #[serde(skip_serializing_if)]) to ensure PII fields are omitted. Combine these practices with DynamoDB’s encryption at rest and IAM policies to enforce least privilege, reducing the risk of PII leakage across storage, retrieval, and logging paths.

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

How does Axum accidentally expose PII when using DynamoDB?
Axum handlers often deserialize full DynamoDB items into structs and return them directly; if those structs contain PII fields and responses include the full item or a broad subset, PII is exposed. Over-broad queries, GSIs with default projections, and logging of responses can further leak PII.
What DynamoDB settings help reduce PII leakage risk?
Use explicit projection expressions to limit retrieved attributes, enable encryption at rest, apply least-privilege IAM policies, avoid scanning all attributes, and restrict GSI projections to only necessary keys or public fields.