MEDIUM log injectionaxum

Log Injection in Axum

How Log Injection Manifests in Axum

Log injection in Axum occurs when untrusted user input flows directly into log statements without proper sanitization. This manifests in several specific ways within Axum applications:

async fn handle_request(
    Extension(logger): Extension, 
    Json(payload): Json<Request>,
) -> Result<impl IntoResponse> {
    // Vulnerable: user-controlled data in log message
    logger.info("Processing request from {} with data: {}", 
               payload.user_id, payload.data);
    
    Ok("")
}

The critical vulnerability here is that payload.data can contain any characters, including newlines and control characters. An attacker could submit:

{
  "user_id": "123",
  "data": "normal data\nERROR: Critical system failure\nStack trace: ..."
}

This creates false log entries that could trigger alerts, hide malicious activity, or cause log parsers to fail. In Axum specifically, this often occurs in:

  • Request logging middleware with user data in log messages
  • Error handling that logs request bodies or query parameters
  • Authentication middleware that logs user identifiers
  • Database operation logging that includes user-supplied values

Axum's extractor-based design makes this particularly common because developers naturally want to log the extracted data:

async fn process_order(
    Path(order_id): Path<String>, 
    Json(order): Json<Order>,
    Extension(logger): Extension<Logger>,
) -> Result<impl IntoResponse> {
    // Vulnerable: order_id from URL path is user-controlled
    logger.info("Processing order {} for user {}", order_id, order.user_id);
    
    // More dangerous: entire JSON body in logs
    logger.info("Received order data: {}", serde_json::to_string(&order)?);
    
    Ok("")
}

The second log statement is especially dangerous because it logs the entire request body, which could contain malicious content designed to break log parsers or inject false security events.

Axum-Specific Detection

Detecting log injection in Axum applications requires both static analysis and runtime monitoring. Static analysis tools can scan for patterns like:

// Pattern: logger.info!(... user-controlled data ...)
logger.info!("{}", user_input);
logger.warn!("Error processing {}: {}", id, user_data);
error!("Failed request: {}", serde_json::to_string(&request)?);

middleBrick's black-box scanning approach tests for log injection by sending payloads with newline characters and control sequences to API endpoints, then analyzing the response logs for injection artifacts. For Axum applications specifically, middleBrick:

  1. Identifies endpoints that log request data based on response patterns
  2. Sends payloads containing newline sequences and log injection patterns
  3. Analyzes response times and error messages for injection indicators
  4. Checks if log levels are improperly exposed in API responses

Runtime detection in production Axum applications should include:

use tracing_subscriber::fmt::format::FmtSpan;

#[tokio::main]
async fn main() {
    // Configure structured logging with sanitization
    let formatter = FmtSpan::ACTIVE
        .with_target(false)
        .with_level(true);
    
    tracing_subscriber::fmt()
        .with_max_level(Level::INFO)
        .with_span_events(formatter)
        .with_filter(tracing_subscriber::filter::EnvFilter::from_default_env())
        .init();
    
    // Start Axum app
    let app = axum::Router::new()
        .route(...);
    
    axum::Server::bind(&([127, 0, 0, 1], 3000).into())
        .serve(app.into_make_service())
        .await
        .unwrap();
}

For comprehensive security testing, middleBrick's continuous monitoring (Pro plan) can automatically scan your Axum APIs on a schedule, catching log injection vulnerabilities before they reach production. The GitHub Action integration allows you to fail builds when suspicious log patterns are detected during testing.

Axum-Specific Remediation

Remediating log injection in Axum requires a multi-layered approach. The most effective strategy combines input sanitization, structured logging, and careful log message construction:

use tracing::{info, warn, error};
use sanitizer::Sanitizer;

// Sanitize user input before logging
fn sanitize_for_log(input: &str) -> String {
    input
        .replace('\n', " ")
        .replace('\r', " ")
        .replace('\t', " ")
        .chars()
        .take(1000) // Limit length
        .collect()
}

async fn secure_logging_example(
    Json(payload): Json<Request>,
    Extension(logger): Extension<Logger>,
) -> Result<impl IntoResponse> {
    // Sanitize before logging
    let safe_user_id = sanitize_for_log(&payload.user_id);
    let safe_data = sanitize_for_log(&payload.data);
    
    // Use structured logging instead of string interpolation
    info!(
        message = "Processing request",
        user_id = %safe_user_id,
        data_length = payload.data.len(),
        data_preview = &safe_data[..std::cmp::min(100, safe_data.len())]
    );
    
    Ok("")
}

The structured logging approach above prevents injection by using key-value pairs instead of string formatting. The sanitize_for_log function removes dangerous characters and limits length.

For Axum applications using middleware, implement a logging middleware that sanitizes automatically:

use axum::{middleware::Next, Request, Response};
use http::{StatusCode, HeaderMap};
use tracing::{info, warn};

async fn logging_middleware(
    req: Request,
    next: Next,
) -> Result<Response, axum::BoxError> {
    let start = std::time::Instant::now();
    let method = req.method().clone();
    let path = req.uri().path().to_string();
    let headers = req.headers().clone();
    
    let response = next.run(req).await;
    
    let status = response.as_ref().map(|r| r.status()).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
    let duration = start.elapsed();
    
    // Sanitize headers before logging
    let safe_headers: Vec<_> = headers
        .into_iter()
        .map(|(k, v)| (k.as_str(), v.to_str().unwrap_or("invalid").to_string()))
        .collect();
    
    info!(
        message = "Request completed",
        method = %method,
        path = %path,
        status = %status,
        duration = %duration.as_millis(),
        headers = ?safe_headers
    );
    
    Ok(response?)
}

middleBrick's Pro plan includes continuous monitoring that can alert you when log injection patterns are detected in production, allowing you to respond before attackers exploit vulnerabilities. The CLI tool (npm install -g middlebrick) can be integrated into your CI/CD pipeline to scan Axum applications before deployment.

Frequently Asked Questions

How does log injection differ from other injection attacks in Axum applications?
Log injection specifically targets log files and monitoring systems rather than application execution. While SQL injection modifies database queries and command injection executes system commands, log injection creates false security events, hides malicious activity in log noise, or breaks log parsers. In Axum, this often occurs through request bodies, query parameters, or path parameters that flow directly into log statements without sanitization.
Can middleBrick detect log injection in my Axum API?
Yes, middleBrick's black-box scanning tests for log injection by sending payloads containing newline characters and control sequences to your Axum endpoints. It analyzes responses for injection indicators and checks if log levels are improperly exposed. The continuous monitoring feature (Pro plan) can automatically scan your APIs on a schedule, while the GitHub Action integration allows you to fail builds when suspicious log patterns are detected during testing.