Out Of Bounds Read in Actix with Basic Auth
Out Of Bounds Read in Actix with Basic Auth
An Out Of Bounds Read occurs when an application accesses memory locations outside the intended buffer or data structure. In Actix web applications using Basic Authentication, this can arise when request handling logic incorrectly indexes into buffers, headers, or parsed authentication data. The combination of Basic Auth and unchecked byte-level access is notable because credentials are transmitted in an easily decodable format and often parsed manually or with low-level byte operations, increasing the risk of reading adjacent memory.
During a black-box scan, middleBrick tests unauthenticated endpoints and then authenticated flows using Basic Auth credentials provided by the user. When authentication is handled via raw header parsing (e.g., extracting the base64-encoded token and decoding it into username/password), an Out Of Bounds Read may be triggered if the implementation does not validate buffer lengths or relies on unsafe indexing. For example, scanning an endpoint that expects credentials in a header with malformed base64 input or truncated values can expose memory beyond the allocated slice or array. This can lead to information disclosure, where arbitrary bytes from the process memory are returned in responses, as observed when decoded credentials or adjacent data are inadvertently echoed or logged.
Consider an Actix handler that manually decodes the Authorization header without proper bounds checks:
use actix_web::{web, HttpRequest, HttpResponse};
fn parse_basic_auth_header(req: &HttpRequest) -> Option<(&str, &str)> {
let auth_header = req.headers().get("Authorization")?.to_str().ok()?;
if !auth_header.starts_with("Basic ") {
return None;
}
let encoded = auth_header.trim_start_matches("Basic ");
// Unsafe: base64 decode without length validation on decoded bytes
let decoded = base64::decode(encoded).ok()?;
// Unsafe: split_at without verifying that delimiter exists within bounds
let pos = decoded.iter().position(|&b| b == b':')?;
let (user_bytes, pass_bytes) = decoded.split_at(pos);
// Potential Out Of Bounds Read if pass_bytes is empty or index is at edge
let password = std::str::from_utf8(&pass_bytes[1..]).ok()?;
Some((std::str::from_utf8(user_bytes).ok()?, password))
}
In this pattern, if the colon index is at the end of the decoded buffer, pass_bytes[1..] may read beyond the allocated slice, resulting in an Out Of Bounds Read. MiddleBrick’s checks for Input Validation and Data Exposure can detect anomalies in how Basic Auth credentials are handled, especially when malformed inputs trigger unexpected memory reads.
Another scenario involves numeric identifiers derived from authentication context being used in array or vector indexing without validation. For instance, mapping a user’s parsed credential to an in-memory session or configuration structure using an unchecked offset can produce similar memory safety issues. Since middleBrick runs 12 security checks in parallel, findings related to BOLA/IDOR and Input Validation are surfaced alongside Data Exposure to highlight cases where out-of-bounds reads may leak sensitive information through API responses.
Basic Auth-Specific Remediation in Actix
Remediation focuses on avoiding manual byte-level parsing and using safe, validated libraries for Basic Authentication. Always prefer established crates that handle decoding and splitting with explicit length checks. Validate the presence of the delimiter before slicing, and ensure that decoded values fit within expected formats before indexing.
Use actix-web::http::header::Authorization and the basic_auth crate to safely parse credentials. This approach eliminates manual base64 decoding and index arithmetic, thereby removing the vector for Out Of Bounds Reads.
Safe Actix Basic Auth example:
use actix_web::{web, HttpRequest, HttpResponse, Error};
use basic_auth::Auth;
async fn safe_auth_handler(req: HttpRequest) -> Result<HttpResponse, Error> {
let auth = Auth::parse(&req);
match auth {
Ok(credentials) => {
let user = credentials.user_id();
let pass = credentials.password().unwrap_or("");
// Proceed with validated user and pass
Ok(HttpResponse::Ok().body(format!("User: {}, Pass: {}", user, pass)))
}
Err(_) => Ok(HttpResponse::Unauthorized().body("Invalid authentication")),
}
}
If you must work with raw headers, enforce strict bounds checks and avoid unchecked indexing:
use actix_web::{HttpRequest, HttpResponse};
fn safe_parse_basic_auth(req: &HttpRequest) -> Option<(&str, &str> {
let header = req.headers().get("Authorization")?.to_str().ok()?;
if !header.starts_with("Basic ") {
return None;
}
let encoded = &header[6..];
let decoded = base64::decode(encoded).ok()?;
// Ensure colon exists and is not at the boundaries
if decoded.is_empty() {
return None;
}
let pos = decoded.iter().position(|&b| b == b':')?;
if pos == 0 || pos == decoded.len() - 1 {
return None;
}
let (user, pass_with_colon) = decoded.split_at(pos);
let pass = &pass_with_colon[1..]; // safe: pos is at least 1 and pass has at least one byte after colon
Some((
std::str::from_utf8(user).ok()?,
std::str::from_utf8(pass).ok()?,
))
}
Additionally, configure the middleware to reject requests with malformed Authorization headers and integrate middleBrick’s GitHub Action to enforce security thresholds in CI/CD. This ensures that any regression introducing unsafe parsing is caught before deployment.