Out Of Bounds Read in Axum
How Out Of Bounds Read Manifests in Axum
Out Of Bounds Read vulnerabilities in Axum applications typically arise from improper handling of request parameters and body parsing. When Axum extracts data from HTTP requests, developers must ensure bounds checking is performed before accessing arrays, vectors, or string slices.
A common manifestation occurs in path parameter extraction. Consider an endpoint that accepts an array index:
use axum::extract::Path;
#[derive(serde::Deserialize)]
struct Params {
index: usize,
items: Vec<String>,
}
async fn get_item(Params { index, items }: Path<Params>) -> String {
// Vulnerable: no bounds check
items[index].clone()
}
If a client requests /items/999 with only 10 items, this triggers an OOB read, potentially exposing memory contents or causing a crash. Axum's extractors don't automatically validate array bounds.
JSON body parsing presents another vector. When deserializing into structs with Vec fields, Axum relies on serde. An attacker can craft oversized arrays or exploit integer parsing:
use axum::extract::Json;
use serde::Deserialize;
#[derive(Deserialize)]
struct Request {
data: Vec<u8>,
}
async fn process_data(Json(req): Json<Request>) -> String {
// Vulnerable if req.data is empty or index is invalid
format!("{:02x}", req.data[0])
}
The vulnerability here is that serde will happily deserialize any array size, but the handler assumes valid indices exist. This becomes critical when the data influences control flow or is used in subsequent operations.
Axum-Specific Detection
Detecting Out Of Bounds Read vulnerabilities in Axum requires both static analysis and runtime scanning. Static analysis tools can identify patterns where array access lacks bounds checking, but runtime scanning reveals actual exploitable conditions.
middleBrick's black-box scanning approach is particularly effective for Axum applications. The scanner sends crafted requests to test array boundaries:
# Scan an Axum API endpoint
middlebrick scan https://api.example.com/items
The scanner tests for:
- Path parameters with extreme values (negative numbers, values exceeding typical array sizes)
- JSON arrays with boundary indices (0, max-1, max, max+1)
- Header values that might be parsed into numeric indices
- Query parameters that control array access
For OpenAPI-aware scanning, middleBrick resolves $ref definitions and tests parameter constraints defined in your Axum application's spec. If your Axum app serves OpenAPI documentation, the scanner cross-references runtime behavior with documented schemas.
Manual detection involves testing endpoints with boundary values. For an endpoint expecting an array index, systematically test:
curl https://api.example.com/items/0
curl https://api.example.com/items/1
curl https://api.example.com/items/999999
Watch for differences in response time, error messages, or unexpected data exposure. Axum's default error handling may reveal stack traces or internal state when bounds checks fail.
Axum-Specific Remediation
Remediation in Axum centers on explicit bounds checking before array access. The framework provides several patterns for safe data handling:
use axum::extract::Path;
use axum::http::StatusCode;
use axum::response::IntoResponse;
async fn get_item(Path((index, items)): Path<(usize, Vec<String>)>) -> impl IntoResponse {
if index >= items.len() {
return (StatusCode::BAD_REQUEST, "Index out of bounds").into_response();
}
items[index].clone()
}
For JSON bodies, validate before processing:
use axum::extract::Json;
use axum::http::StatusCode;
use serde::Deserialize;
#[derive(Deserialize)]
struct Request {
data: Vec<u8>,
}
async fn process_data(Json(req): Json<Request>) -> impl IntoResponse {
if req.data.is_empty() {
return (StatusCode::BAD_REQUEST, "Data array cannot be empty").into_response();
}
format!("{:02x}", req.data[0])
}
Axum's extract::Query and extract::Path extractors can be wrapped with validation:
use axum::extract::{Path, Query};
use serde::Deserialize;
#[derive(Deserialize)]
struct Params {
index: usize,
}
async fn get_item_with_query(
Path(id): Path<String>,
Query(params): Query<Params>,
items: Vec<String>,
) -> impl IntoResponse {
if params.index >= items.len() {
return (StatusCode::BAD_REQUEST, "Invalid index").into_response();
}
items[params.index].clone()
}
For complex validation, create custom extractors that encapsulate bounds checking logic, ensuring consistent security across your Axum application.