HIGH injection flawsactixbasic auth

Injection Flaws in Actix with Basic Auth

Injection Flaws in Actix with Basic Auth

Injection vulnerabilities in Actix when Basic Authentication is used arise when untrusted input from the Authorization header or related request parameters is concatenated into system commands, queries, or dynamic routes. Basic Auth credentials are base64-encoded but not encrypted; they are transmitted in each request and can be decoded easily if intercepted. When endpoints that accept Basic Auth also construct queries or command lines using user-controlled data (e.g., from headers, cookies, or URL segments), injection becomes possible.

For example, consider an Actix handler that decodes Basic Auth and uses the username to build a shell command for user lookup without sanitization:

use actix_web::{web, App, HttpResponse, HttpServer, Responder};
use base64::prelude::*;

async fn user_info(headers: actix_web::HttpRequest) -> impl Responder {
    if let Some(auth) = headers.headers().get("authorization") {
        if let Ok(auth_str) = auth.to_str() {
            if auth_str.starts_with("Basic ") {
                let encoded = auth_str.trim_start_matches("Basic ");
                if let Ok(decoded) = BASE64_STANDARD.decode(encoded) {
                    if let Ok(credentials) = String::from_utf8(decoded) {
                        let parts: Vec<&str> = credentials.split(':').collect();
                        if parts.len() == 2 {
                            let username = parts[0];
                            // Unsafe: username directly interpolated into a shell command
                            let output = std::process::Command::new("id")
                                .arg(username)
                                .output()
                                .expect("failed to execute process");
                            return HttpResponse::Ok().body(format!("User info: {:?}", String::from_utf8_lossy(&output.stdout)));
                        }
                    }
                }
            }
        }
    }
    HttpResponse::Unauthorized().body("Missing or invalid Basic Auth")
}

In this scenario, an attacker who controls the username could attempt command injection (e.g., admin; cat /etc/passwd). Because the handler authenticates via Basic Auth, the attacker may gain access to authenticated endpoints while also injecting malicious commands. This maps to the BFLA/Privilege Escalation and Input Validation checks in middleBrick, which would flag unsafe consumption of authenticated input and improper handling of external data.

Similarly, SQL injection can occur if Basic Auth-derived values are used to build dynamic queries. An Actix handler that concatenates a decoded username into a SQL string is vulnerable:

use sqlx::postgres::PgPoolOptions;

async fn get_user(headers: actix_web::HttpRequest, pool: web::Data) -> actix_web::Result {
    if let Some(auth) = headers.headers().get("authorization") {
        if let Ok(auth_str) = auth.to_str() {
            if auth_str.starts_with("Basic ") {
                let encoded = &auth_str[6..];
                if let Ok(decoded) = BASE64_STANDARD.decode(encoded) {
                    if let Ok(credentials) = String::from_utf8(decoded) {
                        let parts: Vec<&str> = credentials.split(':').collect();
                        if parts.len() == 2 {
                            let username = parts[0];
                            // Unsafe: username directly concatenated into SQL
                            let query = format!("SELECT * FROM users WHERE username = '{}'", username);
                            let user = sqlx::query(&query).fetch_one(pool.get_ref()).await?;
                            return Ok(HttpResponse::Ok().json(user));
                        }
                    }
                }
            }
        }
    }
    Ok(HttpResponse::Unauthorized().body("Unauthorized"))
}

This pattern is commonly flagged under SQL Injection within the Input Validation check. middleBrick would detect the lack of parameterized queries and highlight the risk of data exposure or unauthorized access. Attack patterns like CVE-2023-23969 illustrate how injection via improperly handled inputs can lead to unauthorized data access or manipulation.

Finally, injection can occur at the routing or configuration layer if the username influences route generation or middleware behavior. For instance, dynamically registering routes with user-controlled segments may enable path traversal or route confusion:

async fn scoped_service(headers: actix_web::HttpRequest, scope: web::ServiceConfig) {
    if let Some(auth) = headers.headers().get("authorization") {
        if let Ok(auth_str) = auth.to_str() {
            if auth_str.starts_with("Basic ") {
                let encoded = &auth_str[6..];
                if let Ok(decoded) = BASE64_STANDARD.decode(encoded) {
                    if let Ok(credentials) = String::from_utf8(decoded) {
                        let parts: Vec<&str> = credentials.split(':').collect();
                        if parts.len() == 2 {
                            let org = parts[0];
                            // Unsafe: org used directly in route registration
                            scope.service(
                                web::scope(&org)
                                    .route("/info", web::get()._handler(info_handler)),
                            );
                        }
                    }
                }
            }
        }
    }
}

Such patterns may trigger SSRF or BOLA/IDOR findings in middleBrick if the injected scope leads to unauthorized access to internal services. Remediation requires strict input validation and avoiding dynamic construction of commands, queries, or routes.

Basic Auth-Specific Remediation in Actix

To remediate injection flaws when using Basic Authentication in Actix, avoid direct interpolation of decoded credentials into commands, queries, or routes. Use parameterized APIs and strict validation instead.

1. Use parameterized SQL queries

Replace string formatting with query parameters. This prevents SQL injection even when values originate from Basic Auth:

use sqlx::postgres::PgPoolOptions;
use actix_web::{web, HttpResponse};

async fn get_user_safe(headers: actix_web::HttpRequest, pool: web::Data) -> actix_web::Result {
    if let Some(auth) = headers.headers().get("authorization") {
        if let Ok(auth_str) = auth.to_str() {
            if auth_str.starts_with("Basic ") {
                let encoded = &auth_str[6..];
                if let Ok(decoded) = BASE64_STANDARD.decode(encoded) {
                    if let Ok(credentials) = String::from_utf8(decoded) {
                        let parts: Vec<&str> = credentials.split(':').collect();
                        if parts.len() == 2 {
                            let username = parts[0];
                            // Safe: parameterized query
                            let user = sqlx::query("SELECT * FROM users WHERE username = $1")
                                .bind(username)
                                .fetch_one(pool.get_ref())
                                .await?;
                            return Ok(HttpResponse::Ok().json(user));
                        }
                    }
                }
            }
        }
    }
    Ok(HttpResponse::Unauthorized().body("Unauthorized"))
}

2. Avoid shell command construction

Never pass user-controlled values directly to command arguments. If system interaction is required, use a controlled allowlist:

use actix_web::{web, HttpResponse};
use std::process::Command;

async fn safe_id_lookup(headers: actix_web::HttpRequest) -> HttpResponse {
    if let Some(auth) = headers.headers().get("authorization") {
        if let Ok(auth_str) = auth.to_str() {
            if auth_str.starts_with("Basic ") {
                let encoded = auth_str.trim_start_matches("Basic ");
                if let Ok(decoded) = BASE64_STANDARD.decode(encoded) {
                    if let Ok(credentials) = String::from_utf8(decoded) {
                        let parts: Vec<&str> = credentials.split(':').collect();
                        if parts.len() == 2 {
                            let username = parts[0];
                            // Allowlist validation
                            if username.chars().all(|c| c.is_alphanumeric()) {
                                let output = Command::new("id")
                                    .arg(username)
                                    .output()
                                    .expect("failed to execute process");
                                return HttpResponse::Ok().body(format!("User info: {:?}", String::from_utf8_lossy(&output.stdout)));
                            } else {
                                return HttpResponse::BadRequest().body("Invalid username");
                            }
                        }
                    }
                }
            }
        }
    }
    HttpResponse::Unauthorized().body("Missing or invalid Basic Auth")
}

3. Validate and constrain inputs

Ensure decoded credentials conform to expected patterns before use. Reject usernames containing special characters or path segments to mitigate injection and SSRF risks.

Using these practices reduces findings in the Input Validation, BFLA/Privilege Escalation, and SSRF checks that middleBrick reports on. Note that middleBrick detects these issues and provides remediation guidance but does not alter application behavior.

Frequently Asked Questions

Why does Basic Auth increase injection risk in Actix endpoints?
Because Basic Auth provides an authenticated context that may encourage developers to trust decoded credentials and concatenate them into commands, queries, or routes without validation, enabling injection.
Does middleBrick fix injection flaws found in Actix apps?
No. middleBrick detects and reports injection findings with severity, impact, and remediation guidance. It does not modify code, block requests, or patch the application.