HIGH bola idoraxum

Bola Idor in Axum

How Bola Idor Manifests in Axum

BOLA/IdOR (Broken Object Level Authorization / Insecure Direct Object References) vulnerabilities occur when an API fails to properly verify that a user has permission to access a specific object. In Axum applications, these vulnerabilities often manifest through improper extraction of user identifiers from request paths or query parameters without validating ownership.

A common pattern in Axum involves extracting IDs directly from path parameters and using them to query databases without verifying the resource belongs to the authenticated user. Consider this vulnerable Axum endpoint:

use axum::routing::get;
use axum::Json;
use serde::Deserialize;

#[derive(Deserialize)]
struct GetOrderParams {
    order_id: i32,
}

async fn get_order(
    Path(params): axum::extract::Path<GetOrderParams>,
    db: sqlx::PgPool,
) -> Json<serde_json::Value> {
    let order = sqlx::query_as!(
        Order,
        "SELECT * FROM orders WHERE id = $1",
        params.order_id
    )
    .fetch_one(&db)
    .await
    .unwrap();
    
    Json(serde_json::json!({ "order": order }))
}

#[tokio::main]
async fn main() {
    let app = axum::Router::new()
        .route("/orders/:order_id", get(get_order));
    
    axum::Server::bind(&[([127, 0, 0, 1], 3000).into()])
        .serve(app.into_make_service())
        .await
        .unwrap();
}

This endpoint is vulnerable because it accepts any order_id without verifying the authenticated user owns that order. An attacker could simply increment the order ID in the URL to access other users' orders.

Another Axum-specific manifestation occurs with extractor chaining. When combining multiple extractors, developers sometimes assume the order of extraction provides security:

use axum::extract::{Path, Query};
use axum::Json;

async fn get_user_data(
    Path(user_id): Path<i32>,
    Query(params): Query<HashMap<String, String>>,
    db: sqlx::PgPool,
) -> Json<serde_json::Value> {
    let data = sqlx::query_as!(
        UserData,
        "SELECT * FROM user_data WHERE user_id = $1",
        user_id
    )
    .fetch_one(&db)
    .await
    .unwrap();
    
    Json(serde_json::json!({ "data": data }))
}

The vulnerability here is that user_id comes directly from the URL path without any ownership verification against the authenticated session.

Batch operations in Axum can also introduce BOLA/IdOR vulnerabilities. When processing multiple IDs in a single request, each ID must be validated individually:

use axum::Json;
use serde::Deserialize;

#[derive(Deserialize)]
struct BatchDelete {
    ids: Vec<i32>,
}

async fn delete_orders(
    Json(payload): Json<BatchDelete>,
    db: sqlx::PgPool,
    auth_user: AuthenticatedUser,
) -> Json<serde_json::Value> {
    for id in payload.ids {
        // VULNERABLE: No per-ID authorization check
        sqlx::query("DELETE FROM orders WHERE id = $1")
            .bind(id)
            .execute(&db)
            .await
            .unwrap();
    }
    
    Json(serde_json::json!({ "deleted": payload.ids.len() }))
}

This batch endpoint allows an attacker to delete any orders by providing a list of IDs they don't own.

Axum-Specific Detection

Detecting BOLA/IdOR vulnerabilities in Axum applications requires examining how path parameters and query parameters are extracted and used without proper authorization checks. The most effective approach combines static analysis of your Axum route definitions with runtime scanning.

Static analysis should focus on route patterns that accept IDs directly from URLs. In Axum, this means examining all route() definitions that include path parameters:

use axum::Router;

let app = Router::new()
    .route("/users/:id", get(get_user))
    .route("/posts/:post_id/comments/:comment_id", get(get_comment))
    .route("/orders/:order_id/items/:item_id", get(get_order_item));

Each of these routes is a potential BOLA/IdOR vulnerability if the corresponding handler doesn't verify ownership. Look for patterns where path parameters are directly passed to database queries without validation against the authenticated user.

Runtime scanning with middleBrick can automatically detect these vulnerabilities without requiring access to your source code. middleBrick's black-box scanning tests the unauthenticated attack surface by systematically modifying ID parameters in API requests:

$ middlebrick scan https://api.example.com

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
B F L A / P R I V I L E G E   E S C A L A T I O N
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Risk: High
Category: BOLA / IDOR
Endpoint: GET /users/:id
Parameter: id
Severity: High
Remediation: Verify resource ownership before returning data

Risk: High
Category: BOLA / IDOR
Endpoint: DELETE /orders/:order_id
Parameter: order_id
Severity: Critical
Remediation: Implement authorization middleware to check user ownership

middleBrick's scanning engine automatically tests ID manipulation patterns by incrementing numeric IDs, modifying UUIDs, and testing common ID enumeration techniques. This black-box approach works regardless of whether your Axum application uses authentication middleware, JWT tokens, or session-based auth.

For Axum applications specifically, middleBrick examines the OpenAPI/Swagger specification if available, mapping path parameters to their usage in handler functions and identifying potential authorization bypasses.

Axum-Specific Remediation

Remediating BOLA/IdOR vulnerabilities in Axum requires implementing proper authorization checks before accessing resources. The most effective approach uses Axum's middleware system to centralize authorization logic.

First, create an authorization middleware that verifies resource ownership:

use axum::extract::Path;
use axum::middleware::Next;
use axum::response::IntoResponse;
use axum::http::StatusCode;
use serde::Deserialize;

#[derive(Deserialize)]
struct GetOrderParams {
    order_id: i32,
}

async fn authorize_order_owner(
    Path(params): Path<GetOrderParams>,
    auth_user: AuthenticatedUser,
    db: sqlx::PgPool,
    next: Next,
) -> impl IntoResponse {
    // Check if the order belongs to the authenticated user
    let owner_check = sqlx::query_as!(
        Order,
        "SELECT user_id FROM orders WHERE id = $1",
        params.order_id
    )
    .fetch_optional(&db)
    .await;
    
    match owner_check {
        Ok(Some(order)) if order.user_id == auth_user.id => {
            // User owns this order, proceed to handler
            next.run((params, auth_user, db)).await
        }
        _ => (
            StatusCode::FORBIDDEN,
            "You don't have permission to access this resource",
        ).into_response(),
    }
}

async fn get_order(
    Path(params): Path<GetOrderParams>,
    auth_user: AuthenticatedUser,
    db: sqlx::PgPool,
) -> Json<serde_json::Value> {
    let order = sqlx::query_as!(
        Order,
        "SELECT * FROM orders WHERE id = $1",
        params.order_id
    )
    .fetch_one(&db)
    .await
    .unwrap();
    
    Json(serde_json::json!({ "order": order }))
}

// Apply middleware to specific routes
let app = Router::new()
    .route("/orders/:order_id", get(get_order).layer(authorize_order_owner));

For batch operations, implement per-item authorization checks:

use axum::Json;
use serde::Deserialize;

#[derive(Deserialize)]
struct BatchDelete {
    ids: Vec<i32>,
}

async fn batch_delete_orders(
    Json(payload): Json<BatchDelete>,
    auth_user: AuthenticatedUser,
    db: sqlx::PgPool,
) -> Json<serde_json::Value> {
    let mut deleted_count = 0;
    
    for id in payload.ids {
        // Verify ownership for each ID
        let owner_check = sqlx::query_as!(
            Order,
            "SELECT user_id FROM orders WHERE id = $1",
            id
        )
        .fetch_optional(&db)
        .await;
        
        if let Ok(Some(order)) = owner_check {
            if order.user_id == auth_user.id {
                sqlx::query("DELETE FROM orders WHERE id = $1")
                    .bind(id)
                    .execute(&db)
                    .await
                    .unwrap();
                deleted_count += 1;
            }
        }
    }
    
    Json(serde_json::json!({ 
        "deleted": deleted_count,
        "total_requested": payload.ids.len()
    }))
}

For Axum applications using extractors, create reusable authorization extractors:

use axum::extract::Path;
use axum::Json;
use serde::Deserialize;

#[derive(Deserialize)]
struct OrderId {
    order_id: i32,
}

async fn extract_order_with_auth(
    Path(params): Path<OrderId>,
    auth_user: AuthenticatedUser,
    db: sqlx::PgPool,
) -> Result<(i32, AuthenticatedUser, sqlx::PgPool), StatusCode> {
    let order = sqlx::query_as!(
        Order,
        "SELECT * FROM orders WHERE id = $1",
        params.order_id
    )
    .fetch_optional(&db)
    .await?;
    
    match order {
        Some(order) if order.user_id == auth_user.id => {
            Ok((params.order_id, auth_user, db))
        }
        _ => Err(StatusCode::FORBIDDEN),
    }
}

async fn get_order_with_auth(
    (order_id, auth_user, db): (i32, AuthenticatedUser, sqlx::PgPool),
) -> Json<serde_json::Value> {
    let order = sqlx::query_as!(
        Order,
        "SELECT * FROM orders WHERE id = $1",
        order_id
    )
    .fetch_one(&db)
    .await
    .unwrap();
    
    Json(serde_json::json!({ "order": order }))
}

This pattern ensures authorization is checked before the main handler logic executes, preventing BOLA/IdOR vulnerabilities across your entire Axum application.

Related CWEs: bolaAuthorization

CWE IDNameSeverity
CWE-250Execution with Unnecessary Privileges HIGH
CWE-639Insecure Direct Object Reference CRITICAL
CWE-732Incorrect Permission Assignment HIGH

Frequently Asked Questions

How does middleBrick detect BOLA/IdOR vulnerabilities in Axum applications?
middleBrick performs black-box scanning by systematically modifying ID parameters in API requests. It tests numeric ID incrementing, UUID manipulation, and common enumeration patterns without requiring source code access. The scanner identifies endpoints with path parameters and tests whether they return unauthorized data when IDs are modified.
Can I integrate middleBrick scanning into my Axum CI/CD pipeline?
Yes, middleBrick offers a GitHub Action that integrates directly into CI/CD workflows. You can configure it to scan your staging APIs before deployment and fail builds if security scores drop below your threshold. The CLI tool also allows scanning from terminal or scripts, making it easy to automate security checks in your development process.