HIGH sql injectionaxum

Sql Injection in Axum

How Sql Injection Manifests in Axum

SQL Injection vulnerabilities in Axum applications typically occur when user input is incorporated into SQL queries without proper sanitization. In Axum, this often manifests through dynamic query construction using query parameters, path parameters, or JSON request bodies.

Consider this vulnerable Axum handler:

async fn get_user_by_id(
    Extension(pool): Extension,
    id: String,
) -> Result<Json<User>> {
    let query = format!("SELECT * FROM users WHERE id = '{}'", id);
    let row = sqlx::query_as(&query)
        .fetch_one(pool)
        .await?;
    Ok(Json(row))
}

An attacker could exploit this by sending id values like 1' OR '1'='1, causing the query to return all users. The vulnerability stems from using string interpolation (format!) to construct SQL queries.

Another common pattern in Axum involves building queries with conditional logic:

async fn search_users(
    Extension(pool): Extension<PgPool>,
    search: String,
    category: String,
) -> Result<Json<Vec<User>>> {
    let mut query = String::from("SELECT * FROM users WHERE 1=1");
    
    if !search.is_empty() {
        query.push_str(&format!(" AND name LIKE '%{}%'", search));
    }
    if !category.is_empty() {
        query.push_str(&format!(" AND category = '{}'", category));
    }
    
    let rows = sqlx::query_as(&query)
        .fetch_all(pool)
        .await?;
    Ok(Json(rows))
}

This approach is fundamentally unsafe. An attacker could manipulate the search or category parameters to inject arbitrary SQL, potentially dropping tables, modifying data, or extracting sensitive information.

Even with parameterized queries, developers sometimes make mistakes. For example:

async fn get_user_by_id(
    Extension(pool): Extension<PgPool>,
    id: String,
) -> Result<Json<User>> {
    let query = format!("SELECT * FROM users WHERE id = $1", id);
    let row = sqlx::query_as("SELECT * FROM users WHERE id = $1")
        .bind(id)
        .fetch_one(pool)
        .await?;
    Ok(Json(row))
}

This code appears safe but is vulnerable to SQL injection because the format! macro is used unnecessarily, creating confusion about whether parameterization is actually being used.

Axum-Specific Detection

Detecting SQL Injection in Axum applications requires examining both the source code and runtime behavior. For source code analysis, look for these patterns:

grep -r "format!" src/ | grep -E "(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP)"

This command finds dynamic SQL construction patterns. More specifically, search for:

grep -r "query_as(" src/ | grep -E "(format|push_str|to_string)"

middleBrick's scanner can automatically detect these patterns by analyzing your API endpoints. When you scan an Axum application, middleBrick examines the request handling code and identifies unsafe query construction patterns.

For runtime detection, middleBrick performs active probing by sending specially crafted payloads to test for SQL injection vulnerabilities. For example, it might send:

POST /api/users
Content-Type: application/json

{"search": "' OR '1'='1", "category": "' OR '1'='1"}

If the API returns unexpected results or error messages containing SQL syntax, this indicates a potential vulnerability. middleBrick's LLM/AI security module also checks for SQL injection in AI-powered endpoints, testing whether malicious SQL can be injected through natural language queries.

Another detection technique involves examining error responses. If your Axum application returns detailed database error messages to clients, this can leak information about your database structure and help attackers craft more effective SQL injection attacks.

Axum-Specific Remediation

The proper way to prevent SQL Injection in Axum is to use parameterized queries exclusively. Here's the secure version of the earlier examples:

async fn get_user_by_id(
    Extension(pool): Extension<PgPool>,
    id: String,
) -> Result<Json<User>> {
    let row = sqlx::query_as("SELECT * FROM users WHERE id = $1")
        .bind(id)
        .fetch_one(pool)
        .await?;
    Ok(Json(row))
}

For conditional queries, use parameterized conditions:

async fn search_users(
    Extension(pool): Extension<PgPool>,
    search: Option<String>,
    category: Option<String>,
) -> Result<Json<Vec<User>>> {
    let mut query = String::from("SELECT * FROM users WHERE 1=1");
    let mut params = Vec::new();
    
    if let Some(search) = search {
        query.push_str(" AND name ILIKE $");
        params.push({"%" .to_string() + &search + "%"});
    }
    if let Some(category) = category {
        query.push_str(" AND category = $");
        params.push(category);
    }
    
    let rows = sqlx::query_as(&query)
        .bind_all(params)
        .fetch_all(pool)
        .await?;
    Ok(Json(rows))
}

middleBrick's CLI tool can help verify your remediation:

middlebrick scan https://your-axum-api.com

This scans your running API and provides a security score with specific findings about SQL injection vulnerabilities. The tool checks whether your queries are properly parameterized and whether error messages reveal sensitive information.

For additional protection, implement input validation using Axum's extractors:

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

#[derive(Deserialize)]
struct UserIdPath {
    id: i32, // Only accept numeric IDs
}

async fn get_user_by_id(
    Extension(pool): Extension<PgPool>,
    Path(UserIdPath { id }): Path<UserIdPath>,
) -> Result<Json<User>> {
    let row = sqlx::query_as("SELECT * FROM users WHERE id = $1")
        .bind(id)
        .fetch_one(pool)
        .await?;
    Ok(Json(row))
}

This approach combines type safety with parameterized queries, providing defense in depth against SQL injection attacks.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Can SQL injection occur in Axum even when using sqlx::query_as?
Yes, if you're using string interpolation or format! to construct the query string before passing it to query_as. The query_as function itself is safe only when you pass the SQL string directly and use .bind() for parameters. Dynamic query construction with format! or concatenation creates vulnerabilities regardless of the query function used.
How does middleBrick detect SQL injection in Axum applications?
middleBrick performs black-box scanning by sending crafted payloads to your API endpoints and analyzing responses for SQL injection indicators. It also examines your OpenAPI spec to identify endpoints that accept parameters that could be used in SQL queries. The scanner tests for common injection patterns and checks whether error messages reveal database structure information.