Fix Improper Error Handling in Axum
Improper error handling in Axum often leads to Information Disclosure. By default, developers frequently propagate raw database or filesystem errors directly to the client via 'anyhow' or string conversion. This reveals stack traces, internal paths, and DB schemas. To fix this, you must implement a centralized error mapper that separates internal logging from external responses.
The Vulnerable Pattern
use axum::{extract::Path, http::StatusCode, response::IntoResponse};// VULNERABLE: Propagating raw error strings to the client async fn get_config(Path(id): Path
) -> Result<String, String> { let content = tokio::fs::read_to_string(format!(“/etc/app/config/{}.json”, id)) .await .map_err(|e| e.to_string())?; // LEAK: Returns ‘No such file or directory (os error 2)’ or path info Ok(content)
}
The Secure Implementation
The fix involves three steps: 1. Create a custom error enum (AppError) to categorize failure states. 2. Implement 'IntoResponse' for this enum to define exactly what the client sees (opaque messages) versus what the server logs (full context). 3. Use 'tracing' or similar crates to capture the raw error details for debugging without exposing them to the HTTP response body. This ensures that even if a database connection fails or a file is missing, the attacker only receives a generic status code.
use ax_um::{http::StatusCode, response::{IntoResponse, Response}, Json}; use serde_json::json; use tracing::error;// SECURE: Custom error enum with opaque client messages enum AppError { NotFound, Internal(anyhow::Error), }
impl IntoResponse for AppError { fn into_response(self) -> Response { let (status, error_message) = match self { AppError::NotFound => (StatusCode::NOT_FOUND, “Resource not found”), AppError::Internal(err) => { error!(“Internal System Error: {:?}”, err); // Log the real error internally (StatusCode::INTERNAL_SERVER_ERROR, “An internal server error occurred”) } };
let body = Json(json!({ "error": error_message })); (status, body).into_response() }}
async fn get_config_secure(Path(id): Path) -> Result<String, AppError> { tokio::fs::read_to_string(format!(“/etc/app/config/{}.json”, id)) .await .map_err(|e| match e.kind() { std::io::ErrorKind::NotFound => AppError::NotFound, _ => AppError::Internal(anyhow::anyhow!(e)), }) }
Your Axum API
might be exposed to Improper Error Handling
74% of Axum apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.