HIGH axumrustsql injection union

Sql Injection Union in Axum (Rust)

Sql Injection Union in Axum with Rust — how this specific combination creates or exposes the vulnerability

SQL injection via UNION-based techniques exploits dynamic query construction in Axum handlers written in Rust. When user-controlled input is concatenated into SQL strings without parameterization, an attacker can append a UNION SELECT payload to read from unrelated tables, bypass authentication, or extract schema details. This risk is present whether you use raw sqlx or an ORM that ultimately builds string-based queries.

Consider an endpoint that retrieves a user by username and appends sorting options directly into the SQL string:

// Unsafe: string concatenation enables UNION-based injection
async fn get_user(conn: &PgPool, username: &str) -> Result<User, Error> {
    let query = format!("SELECT id, name, email FROM users WHERE name = '{}' ORDER BY {}", username, "created_at");
    sqlx::query_as(&query).fetch_one(conn).await
}

An attacker can supply admin' UNION SELECT id, password, email FROM users-- as the username, turning the query into:

SELECT id, name, email FROM users WHERE name = 'admin' UNION SELECT id, password, email FROM users-- ORDER BY created_at

This exposes data from other users. In Rust, using sqlx::query with format strings does not automatically separate SQL structure from data, making UNION-based injection possible. The scanner’s input validation checks flag such patterns by correlating untrusted input with SQL syntax regions and detecting suspicious UNION keywords in runtime probes.

Axum’s routing and extractor model does not inherently protect against this; developers must ensure all SQL is parameterized. Even seemingly benign dynamic ORDER BY or SELECT clauses should be handled via allowlists, not string interpolation. The scanner’s property authorization and input validation checks highlight these weaknesses by mapping data flow from HTTP extractors into SQL execution paths.

Additionally, if the API exposes stack traces or verbose errors, an attacker can refine UNION payloads to infer column counts and types, leading to more precise data exfiltration. This is especially relevant when combined with other checks such as data exposure and encryption, where improperly handled responses may leak sensitive information. The LLM/AI security checks further verify whether models interacting with your API could be tricked into aiding injection via crafted prompts that manipulate error messages or schema introspection.

Rust-Specific Remediation in Axum — concrete code fixes

Remediation centers on strict separation of SQL code and data using parameterized queries and allowlists for non-value components. In Rust with sqlx, always use query parameters for user input and avoid format strings for SQL structure.

Safe Axum handler using parameterized queries:

use axum::extract::Query;
use serde::Deserialize;
use sqlx::PgPool;

#[derive(Deserialize)]
struct UserParams {
    name: String,
    sort_field: String, // validate against an allowlist
}

async fn get_user(
    Query(params): Query<UserParams>,
    pool: &State<PgPool>
) -> Result<impl IntoResponse, (StatusCode, String)> {
    // Allowlist for dynamic SQL parts
    let order_field = match params.sort_field.as_str() {
        "created_at" | "name" | "email" => params.sort_field,
        _ => return Err((StatusCode::BAD_REQUEST, "Invalid sort field".into())),
    };
    // Parameterized query for values; string interpolation only for trusted allowlist values
    let query = format!(
        "SELECT id, name, email FROM users WHERE name = $1 ORDER BY {}",
        order_field
    );
    let user = sqlx::query_as(&query)
        .bind(&params.name)
        .fetch_one(&pool)
        .await
        .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))?;
    Ok(Json(user))
}

Key points:

  • Use $1, $2 style placeholders for all user-supplied values; never embed them via format! or string concatenation.
  • For dynamic identifiers (e.g., column or table names), use an allowlist pattern as shown; do not pass raw user input into SQL structure.
  • Leverage Rust’s type system: sqlx::query_as deserializes rows into structs, reducing manual parsing errors.
  • Combine with the CLI (middlebrick scan <url>) to validate that your handlers no longer expose concatenated SQL paths. The dashboard can track risk scores over time to confirm remediation.

For broader protection, integrate the GitHub Action to fail CI/CD pipelines when risk scores drop below your chosen threshold, ensuring new endpoints follow the same safe patterns. The MCP Server allows you to scan APIs directly from your Rust development environment, surfacing issues before code is committed.

Frequently Asked Questions

Can middlebrick detect SQL injection in Axum endpoints during a scan?
Yes. middleBrick runs input validation and property authorization checks that correlate HTTP inputs with SQL execution paths, flagging concatenated queries and UNION-based patterns without requiring authentication.
Does middlebrick fix SQL injection vulnerabilities in Rust code?
No. middleBrick detects and reports findings with remediation guidance. Developers must apply fixes such as parameterized queries and allowlists in Axum handlers.