HIGH denial of serviceaxumdynamodb

Denial Of Service in Axum with Dynamodb

Denial Of Service in Axum with Dynamodb — how this specific combination creates or exposes the vulnerability

Axum is a Rust web framework that encourages fast, non-blocking request handling. When an Axum service calls DynamoDB as a backend dependency, DoS risks arise from unbounded concurrency, long-running synchronous wait paths, and retry storms. A single DynamoDB throttling event can cause worker threads or async tasks to pile up, consuming memory and connection resources until the service becomes unresponsive.

DynamoDB can throttle requests when provisioned capacity is exceeded or when bursts trigger account-level limits. In Axum, if each incoming request performs a strongly consistent read or a write without concurrency control, the resulting retry backoff and queueing can saturate the runtime. For example, a missing index query that results in a full table scan on the server side can amplify read units consumption and increase latency, which in turn keeps request futures pinned longer than expected.

The combination is dangerous when Axum endpoints perform inefficient queries (e.g., repeated GetItem calls in a loop) or when SDK clients are not configured with appropriate timeouts and concurrency limits. Without explicit bounds, a burst of traffic that would normally be handled gracefully can cascade into a wider DoS, where legitimate requests are delayed or dropped because runtime resources are exhausted by blocked or retrying calls to DynamoDB.

An attacker does not need authentication to trigger this class of issue. Public endpoints that issue heavy DynamoDB operations—such as search or batch lookups—are especially susceptible. Instrumentation that does not surface per-call latency and error metrics can hide the problem until the service becomes noticeably slow or fails to serve requests.

Dynamodb-Specific Remediation in Axum — concrete code fixes

Apply explicit concurrency limits, timeouts, and backpressure when using DynamoDB from Axum. Use non-blocking SDK clients, bound the number of in-flight requests, and fail fast when downstream pressure is high.

use aws_sdk_dynamodb::Client;
use std::sync::Arc;
use tokio::sync::Semaphore;
use std::time::Duration;
use axum::{routing::get, Router};

struct AppState {
    client: Client,
    table_name: String,
    concurrency_limit: Arc,
}

async fn get_item_handler(
    state: Arc<AppState>,
    axum::extract::Path(key): axum::extract::Path<String>,
) -> Result<impl axum::response::IntoResponse, (axum::http::StatusCode, String)> {
    // Apply backpressure instead of unbounded concurrency
    let _permit = state.concurrency_limit.acquire().await.map_err(|_| {
        (axum::http::StatusCode::SERVICE_UNAVAILABLE, "service overloaded".to_string())
    })?;

    let resp = tokio::time::timeout(
        Duration::from_millis(800),
        state.client.get_item()
            .table_name(&state.table_name)
            .key("id", aws_sdk_dynamodb::types::AttributeValue::S(key))
            .consistent_read(true)
            .send(),
    ).await.map_err(|_| {
        (axum::http::StatusCode::GATEWAY_TIMEOUT, "dynamodb timeout".to_string())
    })??;

    match resp.item() {
        Some(item) => Ok(axum::Json(serde_json::json!({ "item": item }))),
        None => Err((axum::http::StatusCode::NOT_FOUND, "not found".to_string())),
    }
}

#[tokio::main]
async fn main() {
    let config = aws_config::load_from_env().await;
    let client = Client::new(&config);
    let state = Arc::new(AppState {
        client,
        table_name: "widgets".to_string(),
        concurrency_limit: Arc::new(Semaphore::new(50)), // bound parallelism
    });

    let app = Router::new()
        .route("/items/:id", get(get_item_handler))
        .with_state(state);

    axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

In this pattern, the semaphore restricts the number of concurrent requests that can proceed to DynamoDB, preventing thread exhaustion. A per-request timeout ensures that slow or throttled calls do not hold resources indefinitely. Use exponential backoff with jitter in production SDK clients, and prefer Query or BatchGetItem over repeated GetItem calls to reduce request volume.

For higher throughput, enable client-side caching for read-heavy paths and design indexes to avoid full table scans. Monitor consumed read capacity units and set alarms so you can react before queue lengths grow. These practices reduce the likelihood that a burst of traffic or a downstream throttle event turns into a service-wide denial of service in Axum services that rely on DynamoDB.

Related CWEs: resourceConsumption

CWE IDNameSeverity
CWE-400Uncontrolled Resource Consumption HIGH
CWE-770Allocation of Resources Without Limits MEDIUM
CWE-799Improper Control of Interaction Frequency MEDIUM
CWE-835Infinite Loop HIGH
CWE-1050Excessive Platform Resource Consumption MEDIUM

Frequently Asked Questions

Why does DynamoDB throttling cause DoS in an Axum service?
When DynamoDB throttles requests, Axum futures waiting for responses can accumulate, consuming memory and runtime capacity. Without concurrency limits and timeouts, this backlog can exhaust threads or memory, making the service unresponsive to new traffic.
How can I detect DoS risks that involve DynamoDB in my Axum API?
Use middleBrick to scan your API endpoints. It runs unauthenticated checks across multiple categories, including Input Validation and Rate Limiting, and maps findings to frameworks like OWASP API Top 10. In the dashboard or via the CLI (middlebrick scan <url>), review per-category breakdowns and prioritized remediation guidance.